diff options
655 files changed, 27014 insertions, 91102 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x b/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x index c0c1ea924535..d512f865600e 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x +++ b/Documentation/ABI/testing/sysfs-bus-iio-chemical-vz89x @@ -1,7 +1,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_concentration_VOC_short_raw Date: September 2015 KernelVersion: 4.3 -Contact: Matt Ranostay <mranostay@gmail.com> +Contact: Matt Ranostay <matt.ranostay@konsulko.com> Description: Get the raw calibration VOC value from the sensor. This value has little application outside of calibration. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 index 147d4e8a1403..9a17ab5036a4 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 +++ b/Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935 @@ -1,7 +1,7 @@ What /sys/bus/iio/devices/iio:deviceX/in_proximity_input Date: March 2014 KernelVersion: 3.15 -Contact: Matt Ranostay <mranostay@gmail.com> +Contact: Matt Ranostay <matt.ranostay@konsulko.com> Description: Get the current distance in meters of storm (1km steps) 1000-40000 = distance in meters @@ -9,7 +9,7 @@ Description: What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity Date: March 2014 KernelVersion: 3.15 -Contact: Matt Ranostay <mranostay@gmail.com> +Contact: Matt Ranostay <matt.ranostay@konsulko.com> Description: Show or set the gain boost of the amp, from 0-31 range. 18 = indoors (default) diff --git a/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt b/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt new file mode 100644 index 000000000000..7a6313913923 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/axp20x_adc.txt @@ -0,0 +1,48 @@ +* X-Powers AXP ADC bindings + +Required properties: + - compatible: should be one of: + - "x-powers,axp209-adc", + - "x-powers,axp221-adc", + - "x-powers,axp813-adc", + - #io-channel-cells: should be 1, + +Example: + +&axp22x { + adc { + compatible = "x-powers,axp221-adc"; + #io-channel-cells = <1>; + }; +}; + +ADC channels and their indexes per variant: + +AXP209 +------ + 0 | acin_v + 1 | acin_i + 2 | vbus_v + 3 | vbus_i + 4 | pmic_temp + 5 | gpio0_v + 6 | gpio1_v + 7 | ipsout_v + 8 | batt_v + 9 | batt_chrg_i +10 | batt_dischrg_i + +AXP22x +------ + 0 | pmic_temp + 1 | batt_v + 2 | batt_chrg_i + 3 | batt_dischrg_i + +AXP813 +------ + 0 | pmic_temp + 1 | gpio0_v + 2 | batt_v + 3 | batt_chrg_i + 4 | batt_dischrg_i diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt index 911492da48f3..ed7520d1d051 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.txt @@ -32,6 +32,10 @@ Optional properties: to "clock" property. Frequency must be a multiple of the rcc clock frequency. If not, SPI CLKOUT frequency will not be accurate. +- pinctrl-names: Set to "default". +- pinctrl-0: List of phandles pointing to pin configuration + nodes to set pins in mode of operation for dfsdm + on external pin. Contents of a STM32 DFSDM child nodes: -------------------------------------- @@ -68,8 +72,8 @@ Optional properties: - st,adc-channel-types: Single-ended channel input type. - "SPI_R": SPI with data on rising edge (default) - "SPI_F": SPI with data on falling edge - - "MANCH_R": manchester codec, rising edge = logic 0 - - "MANCH_F": manchester codec, falling edge = logic 1 + - "MANCH_R": manchester codec, rising edge = logic 0, falling edge = logic 1 + - "MANCH_F": manchester codec, rising edge = logic 1, falling edge = logic 0 - st,adc-channel-clk-src: Conversion clock source. - "CLKIN": external SPI clock (CLKIN x) - "CLKOUT": internal SPI clock (CLKOUT) (default) diff --git a/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt b/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt new file mode 100644 index 000000000000..f9b2eef946aa --- /dev/null +++ b/Documentation/devicetree/bindings/iio/potentiometer/ad5272.txt @@ -0,0 +1,27 @@ +* Analog Devices AD5272 digital potentiometer + +The node for this device must be a child node of a I2C controller, hence +all mandatory properties for your controller must be specified. See directory: + + Documentation/devicetree/bindings/i2c + +for more details. + +Required properties: + - compatible: Must be one of the following, depending on the model: + adi,ad5272-020 + adi,ad5272-050 + adi,ad5272-100 + adi,ad5274-020 + adi,ad5274-100 + +Optional properties: + - reset-gpios: GPIO specification for the RESET input. This is an + active low signal to the AD5272. + +Example: +ad5272: potentiometer@2f { + reg = <0x2F>; + compatible = "adi,ad5272-020"; + reset-gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>; +}; diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt new file mode 100644 index 000000000000..0b05812001f8 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt @@ -0,0 +1,28 @@ +* Melexis MLX90632 contactless Infra Red temperature sensor + +Link to datasheet: https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90632 + +There are various applications for the Infra Red contactless temperature sensor +and MLX90632 is most suitable for consumer applications where measured object +temperature is in range between -20 to 200 degrees Celsius with relative error +of measurement below 1 degree Celsius in object temperature range for +industrial applications. Since it can operate and measure ambient temperature +in range of -20 to 85 degrees Celsius it is suitable also for outdoor use. + +Be aware that electronics surrounding the sensor can increase ambient +temperature. MLX90632 can be calibrated to reduce the housing effect via +already existing EEPROM parameters. + +Since measured object emissivity effects Infra Red energy emitted, emissivity +should be set before requesting the object temperature. + +Required properties: + - compatible: should be "melexis,mlx90632" + - reg: the I2C address of the sensor (default 0x3a) + +Example: + +mlx90632@3a { + compatible = "melexis,mlx90632"; + reg = <0x3a>; +}; diff --git a/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-vchiq.txt b/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-vchiq.txt new file mode 100644 index 000000000000..8dd7b3a7de65 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/bcm/brcm,bcm2835-vchiq.txt @@ -0,0 +1,16 @@ +Broadcom VCHIQ firmware services + +Required properties: + +- compatible: Should be "brcm,bcm2835-vchiq" +- reg: Physical base address and length of the doorbell register pair +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + +Example: + +mailbox@7e00b840 { + compatible = "brcm,bcm2835-vchiq"; + reg = <0x7e00b840 0xf>; + interrupts = <0 2>; +}; diff --git a/Documentation/networking/dpaa2/index.rst b/Documentation/networking/dpaa2/index.rst new file mode 100644 index 000000000000..4c6586c87969 --- /dev/null +++ b/Documentation/networking/dpaa2/index.rst @@ -0,0 +1,8 @@ +=================== +DPAA2 Documentation +=================== + +.. toctree:: + :maxdepth: 1 + + overview diff --git a/drivers/staging/fsl-mc/overview.rst b/Documentation/networking/dpaa2/overview.rst index 79fede4447d6..79fede4447d6 100644 --- a/drivers/staging/fsl-mc/overview.rst +++ b/Documentation/networking/dpaa2/overview.rst diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 90966c2692d8..f204eaff657d 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -8,6 +8,7 @@ Contents: batman-adv can + dpaa2/index kapi z8530book msg_zerocopy diff --git a/Documentation/networking/irda.txt b/Documentation/networking/irda.txt deleted file mode 100644 index bff26c138be6..000000000000 --- a/Documentation/networking/irda.txt +++ /dev/null @@ -1,10 +0,0 @@ -To use the IrDA protocols within Linux you will need to get a suitable copy -of the IrDA Utilities. More detailed information about these and associated -programs can be found on http://irda.sourceforge.net/ - -For more information about how to use the IrDA protocol stack, see the -Linux Infrared HOWTO by Werner Heuser <wehe@tuxmobil.org>: -<http://www.tuxmobil.org/Infrared-HOWTO/Infrared-HOWTO.html> - -There is an active mailing list for discussing Linux-IrDA matters called - irda-users@lists.sourceforge.net diff --git a/MAINTAINERS b/MAINTAINERS index f01147af694b..e56cedcd01a0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4370,6 +4370,12 @@ L: linux-kernel@vger.kernel.org S: Maintained F: drivers/staging/fsl-dpaa2/ethernet +DPAA2 ETHERNET SWITCH DRIVER +M: Razvan Stefanescu <razvan.stefanescu@nxp.com> +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/staging/fsl-dpaa2/ethsw + DPT_I2O SCSI RAID DRIVER M: Adaptec OEM Raid Solutions <aacraid@adaptec.com> L: linux-scsi@vger.kernel.org @@ -8587,11 +8593,12 @@ W: https://linuxtv.org S: Maintained F: drivers/media/radio/radio-maxiradio* -MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVER +MCP4018 AND MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVERS M: Peter Rosin <peda@axentia.se> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531 +F: drivers/iio/potentiometer/mcp4018.c F: drivers/iio/potentiometer/mcp4531.c MCR20A IEEE-802.15.4 RADIO DRIVER @@ -8915,6 +8922,13 @@ W: http://www.melexis.com S: Supported F: drivers/iio/temperature/mlx90614.c +MELEXIS MLX90632 DRIVER +M: Crt Mori <cmo@melexis.com> +L: linux-iio@vger.kernel.org +W: http://www.melexis.com +S: Supported +F: drivers/iio/temperature/mlx90632.c + MELFAS MIP4 TOUCHSCREEN DRIVER M: Sangwon Jee <jeesw@melfas.com> W: http://www.melfas.com @@ -11529,8 +11543,9 @@ M: Stuart Yoder <stuyoder@gmail.com> M: Laurentiu Tudor <laurentiu.tudor@nxp.com> L: linux-kernel@vger.kernel.org S: Maintained -F: drivers/staging/fsl-mc/ +F: drivers/bus/fsl-mc/ F: Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt +F: Documentation/networking/dpaa2/overview.rst QT1010 MEDIA DRIVER M: Antti Palosaari <crope@iki.fi> diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi index e36c392a2b8f..593f58d4ac0f 100644 --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi @@ -27,6 +27,12 @@ firmware = <&firmware>; #power-domain-cells = <1>; }; + + mailbox@7e00b840 { + compatible = "brcm,bcm2835-vchiq"; + reg = <0x7e00b840 0xf>; + interrupts = <0 2>; + }; }; }; diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 57e011d36a79..769599bc1bab 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -199,4 +199,6 @@ config DA8XX_MSTPRI configuration. Allows to adjust the priorities of all master peripherals. +source "drivers/bus/fsl-mc/Kconfig" + endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 9bcd0bf3954b..b666c49f249e 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -8,6 +8,10 @@ obj-$(CONFIG_ARM_CCI) += arm-cci.o obj-$(CONFIG_ARM_CCN) += arm-ccn.o obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o + +# DPAA2 fsl-mc bus +obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ + obj-$(CONFIG_IMX_WEIM) += imx-weim.o obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o diff --git a/drivers/bus/fsl-mc/Kconfig b/drivers/bus/fsl-mc/Kconfig new file mode 100644 index 000000000000..c23c77c9b705 --- /dev/null +++ b/drivers/bus/fsl-mc/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# DPAA2 fsl-mc bus +# +# Copyright (C) 2014-2016 Freescale Semiconductor, Inc. +# + +config FSL_MC_BUS + bool "QorIQ DPAA2 fsl-mc bus driver" + depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC))) + select GENERIC_MSI_IRQ_DOMAIN + help + Driver to enable the bus infrastructure for the QorIQ DPAA2 + architecture. The fsl-mc bus driver handles discovery of + DPAA2 objects (which are represented as Linux devices) and + binding objects to drivers. diff --git a/drivers/bus/fsl-mc/Makefile b/drivers/bus/fsl-mc/Makefile new file mode 100644 index 000000000000..3c518c7e8374 --- /dev/null +++ b/drivers/bus/fsl-mc/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Freescale Management Complex (MC) bus drivers +# +# Copyright (C) 2014 Freescale Semiconductor, Inc. +# +obj-$(CONFIG_FSL_MC_BUS) += mc-bus-driver.o + +mc-bus-driver-objs := fsl-mc-bus.o \ + mc-sys.o \ + mc-io.o \ + dpbp.o \ + dpcon.o \ + dprc.o \ + dprc-driver.o \ + fsl-mc-allocator.o \ + fsl-mc-msi.o \ + dpmcp.o diff --git a/drivers/staging/fsl-mc/bus/dpbp.c b/drivers/bus/fsl-mc/dpbp.c index a4df84668d5b..17e3c5d2f22e 100644 --- a/drivers/staging/fsl-mc/bus/dpbp.c +++ b/drivers/bus/fsl-mc/dpbp.c @@ -4,10 +4,10 @@ * */ #include <linux/kernel.h> -#include "../include/mc.h" -#include "../include/dpbp.h" +#include <linux/fsl/mc.h> +#include <linux/fsl/mc.h> -#include "dpbp-cmd.h" +#include "fsl-mc-private.h" /** * dpbp_open() - Open a control session for the specified object. @@ -31,7 +31,7 @@ int dpbp_open(struct fsl_mc_io *mc_io, int dpbp_id, u16 *token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpbp_cmd_open *cmd_params; int err; @@ -68,7 +68,7 @@ int dpbp_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLOSE, cmd_flags, @@ -91,7 +91,7 @@ int dpbp_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_ENABLE, cmd_flags, @@ -114,7 +114,7 @@ int dpbp_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE, @@ -126,40 +126,6 @@ int dpbp_disable(struct fsl_mc_io *mc_io, EXPORT_SYMBOL_GPL(dpbp_disable); /** - * dpbp_is_enabled() - Check if the DPBP is enabled. - * @mc_io: Pointer to MC portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @token: Token of DPBP object - * @en: Returns '1' if object is enabled; '0' otherwise - * - * Return: '0' on Success; Error code otherwise. - */ -int dpbp_is_enabled(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - int *en) -{ - struct mc_command cmd = { 0 }; - struct dpbp_rsp_is_enabled *rsp_params; - int err; - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPBP_CMDID_IS_ENABLED, cmd_flags, - token); - - /* send command to mc*/ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - rsp_params = (struct dpbp_rsp_is_enabled *)cmd.params; - *en = rsp_params->enabled & DPBP_ENABLE; - - return 0; -} -EXPORT_SYMBOL_GPL(dpbp_is_enabled); - -/** * dpbp_reset() - Reset the DPBP, returns the object to initial state. * @mc_io: Pointer to MC portal's I/O object * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' @@ -171,7 +137,7 @@ int dpbp_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET, @@ -197,7 +163,7 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io, u16 token, struct dpbp_attr *attr) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpbp_rsp_get_attributes *rsp_params; int err; @@ -218,36 +184,3 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io, return 0; } EXPORT_SYMBOL_GPL(dpbp_get_attributes); - -/** - * dpbp_get_api_version - Get Data Path Buffer Pool API version - * @mc_io: Pointer to Mc portal's I/O object - * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' - * @major_ver: Major version of Buffer Pool API - * @minor_ver: Minor version of Buffer Pool API - * - * Return: '0' on Success; Error code otherwise. - */ -int dpbp_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver) -{ - struct mc_command cmd = { 0 }; - int err; - - /* prepare command */ - cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_API_VERSION, - cmd_flags, 0); - - /* send command to mc */ - err = mc_send_command(mc_io, &cmd); - if (err) - return err; - - /* retrieve response parameters */ - mc_cmd_read_api_version(&cmd, major_ver, minor_ver); - - return 0; -} -EXPORT_SYMBOL_GPL(dpbp_get_api_version); diff --git a/drivers/staging/fsl-mc/bus/dpcon.c b/drivers/bus/fsl-mc/dpcon.c index 8f84d7b5465c..760555d7946e 100644 --- a/drivers/staging/fsl-mc/bus/dpcon.c +++ b/drivers/bus/fsl-mc/dpcon.c @@ -4,10 +4,10 @@ * */ #include <linux/kernel.h> -#include "../include/mc.h" -#include "../include/dpcon.h" +#include <linux/fsl/mc.h> +#include <linux/fsl/mc.h> -#include "dpcon-cmd.h" +#include "fsl-mc-private.h" /** * dpcon_open() - Open a control session for the specified object @@ -31,7 +31,7 @@ int dpcon_open(struct fsl_mc_io *mc_io, int dpcon_id, u16 *token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpcon_cmd_open *dpcon_cmd; int err; @@ -69,7 +69,7 @@ int dpcon_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPCON_CMDID_CLOSE, @@ -93,7 +93,7 @@ int dpcon_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPCON_CMDID_ENABLE, @@ -117,7 +117,7 @@ int dpcon_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPCON_CMDID_DISABLE, @@ -141,7 +141,7 @@ int dpcon_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPCON_CMDID_RESET, @@ -166,7 +166,7 @@ int dpcon_get_attributes(struct fsl_mc_io *mc_io, u16 token, struct dpcon_attr *attr) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpcon_rsp_get_attr *dpcon_rsp; int err; @@ -204,7 +204,7 @@ int dpcon_set_notification(struct fsl_mc_io *mc_io, u16 token, struct dpcon_notification_cfg *cfg) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpcon_cmd_set_notification *dpcon_cmd; /* prepare command */ diff --git a/drivers/staging/fsl-mc/bus/dpmcp.c b/drivers/bus/fsl-mc/dpmcp.c index be07c77520af..5fbd0dbde24a 100644 --- a/drivers/staging/fsl-mc/bus/dpmcp.c +++ b/drivers/bus/fsl-mc/dpmcp.c @@ -4,7 +4,7 @@ * */ #include <linux/kernel.h> -#include "../include/mc.h" +#include <linux/fsl/mc.h> #include "fsl-mc-private.h" @@ -30,7 +30,7 @@ int dpmcp_open(struct fsl_mc_io *mc_io, int dpmcp_id, u16 *token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpmcp_cmd_open *cmd_params; int err; @@ -66,7 +66,7 @@ int dpmcp_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_CLOSE, @@ -88,7 +88,7 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_RESET, diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c index b09075731e62..52c7e15143d6 100644 --- a/drivers/staging/fsl-mc/bus/dprc-driver.c +++ b/drivers/bus/fsl-mc/dprc-driver.c @@ -11,7 +11,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/msi.h> -#include "../include/mc.h" +#include <linux/fsl/mc.h> #include "fsl-mc-private.h" diff --git a/drivers/staging/fsl-mc/bus/dprc.c b/drivers/bus/fsl-mc/dprc.c index 97f51726fa7e..1c3f62182266 100644 --- a/drivers/staging/fsl-mc/bus/dprc.c +++ b/drivers/bus/fsl-mc/dprc.c @@ -4,7 +4,8 @@ * */ #include <linux/kernel.h> -#include "../include/mc.h" +#include <linux/fsl/mc.h> + #include "fsl-mc-private.h" /** @@ -23,7 +24,7 @@ int dprc_open(struct fsl_mc_io *mc_io, int container_id, u16 *token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_open *cmd_params; int err; @@ -60,7 +61,7 @@ int dprc_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLOSE, cmd_flags, @@ -87,7 +88,7 @@ int dprc_set_irq(struct fsl_mc_io *mc_io, u8 irq_index, struct dprc_irq_cfg *irq_cfg) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_set_irq *cmd_params; /* prepare command */ @@ -125,7 +126,7 @@ int dprc_set_irq_enable(struct fsl_mc_io *mc_io, u8 irq_index, u8 en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_set_irq_enable *cmd_params; /* prepare command */ @@ -161,7 +162,7 @@ int dprc_set_irq_mask(struct fsl_mc_io *mc_io, u8 irq_index, u32 mask) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_set_irq_mask *cmd_params; /* prepare command */ @@ -193,7 +194,7 @@ int dprc_get_irq_status(struct fsl_mc_io *mc_io, u8 irq_index, u32 *status) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_get_irq_status *cmd_params; struct dprc_rsp_get_irq_status *rsp_params; int err; @@ -235,7 +236,7 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io, u8 irq_index, u32 status) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_clear_irq_status *cmd_params; /* prepare command */ @@ -263,7 +264,7 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io, u16 token, struct dprc_attributes *attr) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_rsp_get_attributes *rsp_params; int err; @@ -301,7 +302,7 @@ int dprc_get_obj_count(struct fsl_mc_io *mc_io, u16 token, int *obj_count) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_rsp_get_obj_count *rsp_params; int err; @@ -343,7 +344,7 @@ int dprc_get_obj(struct fsl_mc_io *mc_io, int obj_index, struct fsl_mc_obj_desc *obj_desc) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_get_obj *cmd_params; struct dprc_rsp_get_obj *rsp_params; int err; @@ -398,7 +399,7 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io, u8 irq_index, struct dprc_irq_cfg *irq_cfg) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_set_obj_irq *cmd_params; /* prepare command */ @@ -439,7 +440,7 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, u8 region_index, struct dprc_region_desc *region_desc) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_get_obj_region *cmd_params; struct dprc_rsp_get_obj_region *rsp_params; int err; @@ -481,7 +482,7 @@ int dprc_get_api_version(struct fsl_mc_io *mc_io, u16 *major_ver, u16 *minor_ver) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; int err; /* prepare command */ @@ -511,7 +512,7 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io, u32 cmd_flags, int *container_id) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; int err; /* prepare command */ diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c index 8f313a41240b..fb1442b08962 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c +++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c @@ -8,7 +8,7 @@ #include <linux/module.h> #include <linux/msi.h> -#include "../include/mc.h" +#include <linux/fsl/mc.h> #include "fsl-mc-private.h" @@ -646,3 +646,8 @@ int __init fsl_mc_allocator_driver_init(void) { return fsl_mc_driver_register(&fsl_mc_allocator_driver); } + +void fsl_mc_allocator_driver_exit(void) +{ + fsl_mc_driver_unregister(&fsl_mc_allocator_driver); +} diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 1b333c43aae9..5d8266c6571f 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -314,7 +314,7 @@ static int mc_get_version(struct fsl_mc_io *mc_io, u32 cmd_flags, struct mc_version *mc_ver_info) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpmng_rsp_get_version *rsp_params; int err; diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c b/drivers/bus/fsl-mc/fsl-mc-msi.c index 971ad87c584c..ec35e255b496 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c +++ b/drivers/bus/fsl-mc/fsl-mc-msi.c @@ -13,6 +13,7 @@ #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/msi.h> + #include "fsl-mc-private.h" #ifdef GENERIC_MSI_DOMAIN_OPS diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-private.h b/drivers/bus/fsl-mc/fsl-mc-private.h index 83b89d6241f2..ea11b4fe59f7 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-private.h +++ b/drivers/bus/fsl-mc/fsl-mc-private.h @@ -8,7 +8,7 @@ #ifndef _FSL_MC_PRIVATE_H_ #define _FSL_MC_PRIVATE_H_ -#include "../include/mc.h" +#include <linux/fsl/mc.h> #include <linux/mutex.h> /* @@ -379,6 +379,93 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io, u32 cmd_flags, int *container_id); +/* + * Data Path Buffer Pool (DPBP) API + */ + +/* DPBP Version */ +#define DPBP_VER_MAJOR 3 +#define DPBP_VER_MINOR 2 + +/* Command versioning */ +#define DPBP_CMD_BASE_VERSION 1 +#define DPBP_CMD_ID_OFFSET 4 + +#define DPBP_CMD(id) (((id) << DPBP_CMD_ID_OFFSET) | DPBP_CMD_BASE_VERSION) + +/* Command IDs */ +#define DPBP_CMDID_CLOSE DPBP_CMD(0x800) +#define DPBP_CMDID_OPEN DPBP_CMD(0x804) + +#define DPBP_CMDID_ENABLE DPBP_CMD(0x002) +#define DPBP_CMDID_DISABLE DPBP_CMD(0x003) +#define DPBP_CMDID_GET_ATTR DPBP_CMD(0x004) +#define DPBP_CMDID_RESET DPBP_CMD(0x005) + +struct dpbp_cmd_open { + __le32 dpbp_id; +}; + +#define DPBP_ENABLE 0x1 + +struct dpbp_rsp_get_attributes { + /* response word 0 */ + __le16 pad; + __le16 bpid; + __le32 id; + /* response word 1 */ + __le16 version_major; + __le16 version_minor; +}; + +/* + * Data Path Concentrator (DPCON) API + */ + +/* DPCON Version */ +#define DPCON_VER_MAJOR 3 +#define DPCON_VER_MINOR 2 + +/* Command versioning */ +#define DPCON_CMD_BASE_VERSION 1 +#define DPCON_CMD_ID_OFFSET 4 + +#define DPCON_CMD(id) (((id) << DPCON_CMD_ID_OFFSET) | DPCON_CMD_BASE_VERSION) + +/* Command IDs */ +#define DPCON_CMDID_CLOSE DPCON_CMD(0x800) +#define DPCON_CMDID_OPEN DPCON_CMD(0x808) + +#define DPCON_CMDID_ENABLE DPCON_CMD(0x002) +#define DPCON_CMDID_DISABLE DPCON_CMD(0x003) +#define DPCON_CMDID_GET_ATTR DPCON_CMD(0x004) +#define DPCON_CMDID_RESET DPCON_CMD(0x005) + +#define DPCON_CMDID_SET_NOTIFICATION DPCON_CMD(0x100) + +struct dpcon_cmd_open { + __le32 dpcon_id; +}; + +#define DPCON_ENABLE 1 + +struct dpcon_rsp_get_attr { + /* response word 0 */ + __le32 id; + __le16 qbman_ch_id; + u8 num_priorities; + u8 pad; +}; + +struct dpcon_cmd_set_notification { + /* cmd word 0 */ + __le32 dpio_id; + u8 priority; + u8 pad[3]; + /* cmd word 1 */ + __le64 user_ctx; +}; + /** * Maximum number of total IRQs that can be pre-allocated for an MC bus' * IRQ pool @@ -438,6 +525,8 @@ void dprc_driver_exit(void); int __init fsl_mc_allocator_driver_init(void); +void fsl_mc_allocator_driver_exit(void); + void fsl_mc_init_all_resource_pools(struct fsl_mc_device *mc_bus_dev); void fsl_mc_cleanup_all_resource_pools(struct fsl_mc_device *mc_bus_dev); diff --git a/drivers/staging/fsl-mc/bus/mc-io.c b/drivers/bus/fsl-mc/mc-io.c index 7e6fb360ef12..7226cfc49b6f 100644 --- a/drivers/staging/fsl-mc/bus/mc-io.c +++ b/drivers/bus/fsl-mc/mc-io.c @@ -5,7 +5,7 @@ */ #include <linux/io.h> -#include "../include/mc.h" +#include <linux/fsl/mc.h> #include "fsl-mc-private.h" diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/bus/fsl-mc/mc-sys.c index f09d75d9a976..3221a7fbaf0a 100644 --- a/drivers/staging/fsl-mc/bus/mc-sys.c +++ b/drivers/bus/fsl-mc/mc-sys.c @@ -12,7 +12,7 @@ #include <linux/device.h> #include <linux/io.h> #include <linux/io-64-nonatomic-hi-lo.h> -#include "../include/mc.h" +#include <linux/fsl/mc.h> #include "fsl-mc-private.h" @@ -28,14 +28,14 @@ #define MC_CMD_COMPLETION_POLLING_MIN_SLEEP_USECS 10 #define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500 -static enum mc_cmd_status mc_cmd_hdr_read_status(struct mc_command *cmd) +static enum mc_cmd_status mc_cmd_hdr_read_status(struct fsl_mc_command *cmd) { struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; return (enum mc_cmd_status)hdr->status; } -static u16 mc_cmd_hdr_read_cmdid(struct mc_command *cmd) +static u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd) { struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; u16 cmd_id = le16_to_cpu(hdr->cmd_id); @@ -94,8 +94,8 @@ static const char *mc_status_to_string(enum mc_cmd_status status) * @portal: pointer to an MC portal * @cmd: pointer to a filled command */ -static inline void mc_write_command(struct mc_command __iomem *portal, - struct mc_command *cmd) +static inline void mc_write_command(struct fsl_mc_command __iomem *portal, + struct fsl_mc_command *cmd) { int i; @@ -121,9 +121,9 @@ static inline void mc_write_command(struct mc_command __iomem *portal, * * Returns MC_CMD_STATUS_OK on Success; Error code otherwise. */ -static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem * - portal, - struct mc_command *resp) +static inline enum mc_cmd_status mc_read_response(struct fsl_mc_command __iomem + *portal, + struct fsl_mc_command *resp) { int i; enum mc_cmd_status status; @@ -156,7 +156,7 @@ static inline enum mc_cmd_status mc_read_response(struct mc_command __iomem * * @mc_status: MC command completion status */ static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io, - struct mc_command *cmd, + struct fsl_mc_command *cmd, enum mc_cmd_status *mc_status) { enum mc_cmd_status status; @@ -202,7 +202,7 @@ static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io, * @mc_status: MC command completion status */ static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io, - struct mc_command *cmd, + struct fsl_mc_command *cmd, enum mc_cmd_status *mc_status) { enum mc_cmd_status status; @@ -241,7 +241,7 @@ static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io, * * Returns '0' on Success; Error code otherwise. */ -int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) +int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd) { int error; enum mc_cmd_status status; diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 870f92ef61c2..208f2d9f0e8a 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -336,8 +336,7 @@ static int bmc150_accel_update_slope(struct bmc150_accel_data *data) return ret; } - dev_dbg(dev, "%s: %x %x\n", __func__, data->slope_thres, - data->slope_dur); + dev_dbg(dev, "%x %x\n", data->slope_thres, data->slope_dur); return ret; } @@ -1716,7 +1715,6 @@ static int bmc150_accel_runtime_suspend(struct device *dev) struct bmc150_accel_data *data = iio_priv(indio_dev); int ret; - dev_dbg(dev, __func__); ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); if (ret < 0) return -EAGAIN; @@ -1731,8 +1729,6 @@ static int bmc150_accel_runtime_resume(struct device *dev) int ret; int sleep_val; - dev_dbg(dev, __func__); - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); if (ret < 0) return ret; diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index c066a3bdbff7..41d97faf5013 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -155,7 +155,7 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = 0; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: hid_sensor_power_state(&accel_state->common_attributes, true); report_id = accel_state->accel[chan->scan_index].report_id; address = accel_3d_addresses[chan->scan_index]; diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 363429b5686c..6bdec8c451e0 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -159,9 +159,8 @@ static int st_accel_i2c_probe(struct i2c_client *client, if ((ret < 0) || (ret >= ST_ACCEL_MAX)) return -ENODEV; - strncpy(client->name, st_accel_id_table[ret].name, + strlcpy(client->name, st_accel_id_table[ret].name, sizeof(client->name)); - client->name[sizeof(client->name) - 1] = '\0'; } else if (!id) return -ENODEV; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 72bc2b71765a..914b6f849a29 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -144,10 +144,9 @@ config ASPEED_ADC config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 - depends on INPUT + depends on INPUT && SYSFS select IIO_BUFFER select IIO_TRIGGERED_BUFFER - select SYSFS help Say yes here to build support for Atmel AT91 ADC. diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index b7706bf10ffe..fbaae47746a8 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -1,9 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver + * Analog Devices AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver + * TI ADC081S/ADC101S/ADC121S 8/10/12-bit SPI ADC driver * * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. */ #include <linux/device.h> @@ -56,6 +56,9 @@ enum ad7476_supported_device_ids { ID_AD7468, ID_AD7495, ID_AD7940, + ID_ADC081S, + ID_ADC101S, + ID_ADC121S, }; static irqreturn_t ad7476_trigger_handler(int irq, void *p) @@ -147,6 +150,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, }, \ } +#define ADC081S_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \ + BIT(IIO_CHAN_INFO_RAW)) #define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \ BIT(IIO_CHAN_INFO_RAW)) #define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \ @@ -192,6 +197,18 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { .channel[0] = AD7940_CHAN(14), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, + [ID_ADC081S] = { + .channel[0] = ADC081S_CHAN(8), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + }, + [ID_ADC101S] = { + .channel[0] = ADC081S_CHAN(10), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + }, + [ID_ADC121S] = { + .channel[0] = ADC081S_CHAN(12), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + }, }; static const struct iio_info ad7476_info = { @@ -294,6 +311,9 @@ static const struct spi_device_id ad7476_id[] = { {"ad7910", ID_AD7467}, {"ad7920", ID_AD7466}, {"ad7940", ID_AD7940}, + {"adc081s", ID_ADC081S}, + {"adc101s", ID_ADC101S}, + {"adc121s", ID_ADC121S}, {} }; MODULE_DEVICE_TABLE(spi, ad7476_id); diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index a30a97245e91..5be789269353 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -35,8 +35,13 @@ #define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1) #define AXP20X_ADC_RATE_MASK GENMASK(7, 6) +#define AXP813_V_I_ADC_RATE_MASK GENMASK(5, 4) +#define AXP813_ADC_RATE_MASK (AXP20X_ADC_RATE_MASK | AXP813_V_I_ADC_RATE_MASK) #define AXP20X_ADC_RATE_HZ(x) ((ilog2((x) / 25) << 6) & AXP20X_ADC_RATE_MASK) #define AXP22X_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 6) & AXP20X_ADC_RATE_MASK) +#define AXP813_TS_GPIO0_ADC_RATE_HZ(x) AXP20X_ADC_RATE_HZ(x) +#define AXP813_V_I_ADC_RATE_HZ(x) ((ilog2((x) / 100) << 4) & AXP813_V_I_ADC_RATE_MASK) +#define AXP813_ADC_RATE_HZ(x) (AXP20X_ADC_RATE_HZ(x) | AXP813_V_I_ADC_RATE_HZ(x)) #define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \ { \ @@ -95,6 +100,12 @@ enum axp22x_adc_channel_i { AXP22X_BATT_DISCHRG_I, }; +enum axp813_adc_channel_v { + AXP813_TS_IN = 0, + AXP813_GPIO0_V, + AXP813_BATT_V, +}; + static struct iio_map axp20x_maps[] = { { .consumer_dev_name = "axp20x-usb-power-supply", @@ -197,6 +208,25 @@ static const struct iio_chan_spec axp22x_adc_channels[] = { AXP20X_BATT_DISCHRG_I_H), }; +static const struct iio_chan_spec axp813_adc_channels[] = { + { + .type = IIO_TEMP, + .address = AXP22X_PMIC_TEMP_H, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .datasheet_name = "pmic_temp", + }, + AXP20X_ADC_CHANNEL(AXP813_GPIO0_V, "gpio0_v", IIO_VOLTAGE, + AXP288_GP_ADC_H), + AXP20X_ADC_CHANNEL(AXP813_BATT_V, "batt_v", IIO_VOLTAGE, + AXP20X_BATT_V_H), + AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT, + AXP20X_BATT_CHRG_I_H), + AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT, + AXP20X_BATT_DISCHRG_I_H), +}; + static int axp20x_adc_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val) { @@ -243,6 +273,18 @@ static int axp22x_adc_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; } +static int axp813_adc_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val) +{ + struct axp20x_adc_iio *info = iio_priv(indio_dev); + + *val = axp20x_read_variable_width(info->regmap, chan->address, 12); + if (*val < 0) + return *val; + + return IIO_VAL_INT; +} + static int axp20x_adc_scale_voltage(int channel, int *val, int *val2) { switch (channel) { @@ -273,6 +315,24 @@ static int axp20x_adc_scale_voltage(int channel, int *val, int *val2) } } +static int axp813_adc_scale_voltage(int channel, int *val, int *val2) +{ + switch (channel) { + case AXP813_GPIO0_V: + *val = 0; + *val2 = 800000; + return IIO_VAL_INT_PLUS_MICRO; + + case AXP813_BATT_V: + *val = 1; + *val2 = 100000; + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + static int axp20x_adc_scale_current(int channel, int *val, int *val2) { switch (channel) { @@ -342,6 +402,26 @@ static int axp22x_adc_scale(struct iio_chan_spec const *chan, int *val, } } +static int axp813_adc_scale(struct iio_chan_spec const *chan, int *val, + int *val2) +{ + switch (chan->type) { + case IIO_VOLTAGE: + return axp813_adc_scale_voltage(chan->channel, val, val2); + + case IIO_CURRENT: + *val = 1; + return IIO_VAL_INT; + + case IIO_TEMP: + *val = 100; + return IIO_VAL_INT; + + default: + return -EINVAL; + } +} + static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel, int *val) { @@ -365,7 +445,7 @@ static int axp20x_adc_offset_voltage(struct iio_dev *indio_dev, int channel, return -EINVAL; } - *val = !!(*val) * 700000; + *val = *val ? 700000 : 0; return IIO_VAL_INT; } @@ -425,6 +505,26 @@ static int axp22x_read_raw(struct iio_dev *indio_dev, } } +static int axp813_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_OFFSET: + *val = -2667; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + return axp813_adc_scale(chan, val, val2); + + case IIO_CHAN_INFO_RAW: + return axp813_adc_raw(indio_dev, chan, val); + + default: + return -EINVAL; + } +} + static int axp20x_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -442,15 +542,17 @@ static int axp20x_write_raw(struct iio_dev *indio_dev, if (val != 0 && val != 700000) return -EINVAL; + val = val ? 1 : 0; + switch (chan->channel) { case AXP20X_GPIO0_V: reg = AXP20X_GPIO10_IN_RANGE_GPIO0; - regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val); + regval = AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(val); break; case AXP20X_GPIO1_V: reg = AXP20X_GPIO10_IN_RANGE_GPIO1; - regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val); + regval = AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(val); break; default: @@ -470,14 +572,29 @@ static const struct iio_info axp22x_adc_iio_info = { .read_raw = axp22x_read_raw, }; -static int axp20x_adc_rate(int rate) +static const struct iio_info axp813_adc_iio_info = { + .read_raw = axp813_read_raw, +}; + +static int axp20x_adc_rate(struct axp20x_adc_iio *info, int rate) +{ + return regmap_update_bits(info->regmap, AXP20X_ADC_RATE, + AXP20X_ADC_RATE_MASK, + AXP20X_ADC_RATE_HZ(rate)); +} + +static int axp22x_adc_rate(struct axp20x_adc_iio *info, int rate) { - return AXP20X_ADC_RATE_HZ(rate); + return regmap_update_bits(info->regmap, AXP20X_ADC_RATE, + AXP20X_ADC_RATE_MASK, + AXP22X_ADC_RATE_HZ(rate)); } -static int axp22x_adc_rate(int rate) +static int axp813_adc_rate(struct axp20x_adc_iio *info, int rate) { - return AXP22X_ADC_RATE_HZ(rate); + return regmap_update_bits(info->regmap, AXP813_ADC_RATE, + AXP813_ADC_RATE_MASK, + AXP813_ADC_RATE_HZ(rate)); } struct axp_data { @@ -485,7 +602,8 @@ struct axp_data { int num_channels; struct iio_chan_spec const *channels; unsigned long adc_en1_mask; - int (*adc_rate)(int rate); + int (*adc_rate)(struct axp20x_adc_iio *info, + int rate); bool adc_en2; struct iio_map *maps; }; @@ -510,9 +628,28 @@ static const struct axp_data axp22x_data = { .maps = axp22x_maps, }; +static const struct axp_data axp813_data = { + .iio_info = &axp813_adc_iio_info, + .num_channels = ARRAY_SIZE(axp813_adc_channels), + .channels = axp813_adc_channels, + .adc_en1_mask = AXP22X_ADC_EN1_MASK, + .adc_rate = axp813_adc_rate, + .adc_en2 = false, + .maps = axp22x_maps, +}; + +static const struct of_device_id axp20x_adc_of_match[] = { + { .compatible = "x-powers,axp209-adc", .data = (void *)&axp20x_data, }, + { .compatible = "x-powers,axp221-adc", .data = (void *)&axp22x_data, }, + { .compatible = "x-powers,axp813-adc", .data = (void *)&axp813_data, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, axp20x_adc_of_match); + static const struct platform_device_id axp20x_adc_id_match[] = { { .name = "axp20x-adc", .driver_data = (kernel_ulong_t)&axp20x_data, }, { .name = "axp22x-adc", .driver_data = (kernel_ulong_t)&axp22x_data, }, + { .name = "axp813-adc", .driver_data = (kernel_ulong_t)&axp813_data, }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(platform, axp20x_adc_id_match); @@ -538,7 +675,16 @@ static int axp20x_probe(struct platform_device *pdev) indio_dev->dev.of_node = pdev->dev.of_node; indio_dev->modes = INDIO_DIRECT_MODE; - info->data = (struct axp_data *)platform_get_device_id(pdev)->driver_data; + if (!pdev->dev.of_node) { + const struct platform_device_id *id; + + id = platform_get_device_id(pdev); + info->data = (struct axp_data *)id->driver_data; + } else { + struct device *dev = &pdev->dev; + + info->data = (struct axp_data *)of_device_get_match_data(dev); + } indio_dev->name = platform_get_device_id(pdev)->name; indio_dev->info = info->data->iio_info; @@ -554,8 +700,7 @@ static int axp20x_probe(struct platform_device *pdev) AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK); /* Configure ADCs rate */ - regmap_update_bits(info->regmap, AXP20X_ADC_RATE, AXP20X_ADC_RATE_MASK, - info->data->adc_rate(100)); + info->data->adc_rate(info, 100); ret = iio_map_array_register(indio_dev, info->data->maps); if (ret < 0) { @@ -602,6 +747,7 @@ static int axp20x_remove(struct platform_device *pdev) static struct platform_driver axp20x_adc_driver = { .driver = { .name = "axp20x-adc", + .of_match_table = of_match_ptr(axp20x_adc_of_match), }, .id_table = axp20x_adc_id_match, .probe = axp20x_probe, diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c index 81c901507ad2..5036c392cb20 100644 --- a/drivers/iio/adc/ep93xx_adc.c +++ b/drivers/iio/adc/ep93xx_adc.c @@ -167,10 +167,6 @@ static int ep93xx_adc_probe(struct platform_device *pdev) priv = iio_priv(iiodev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Cannot obtain memory resource\n"); - return -ENXIO; - } priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) { dev_err(&pdev->dev, "Cannot map memory resource\n"); diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index 10fa7677ac4b..3bbc9b9ddbfe 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * ti-adc161s626.c - Texas Instruments ADC161S626 1-channel differential ADC * @@ -5,17 +6,8 @@ * adc141s626 - 14-bit ADC * adc161s626 - 16-bit ADC * - * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2016-2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> */ #include <linux/module.h> @@ -275,6 +267,6 @@ static struct spi_driver ti_adc_driver = { }; module_spi_driver(ti_adc_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("Texas Instruments ADC1x1S 1-channel differential ADC"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c index d9e5950ad24a..a0646ba2ad88 100644 --- a/drivers/iio/chemical/ams-iaq-core.c +++ b/drivers/iio/chemical/ams-iaq-core.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * ams-iaq-core.c - Support for AMS iAQ-Core VOC sensors * - * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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. - * + * Copyright (C) 2015, 2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> */ #include <linux/module.h> @@ -194,6 +185,6 @@ static struct i2c_driver ams_iaqcore_driver = { }; module_i2c_driver(ams_iaqcore_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("AMS iAQ-Core VOC sensors"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index 8c4e05580091..abfc4bbc4cfc 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * atlas-ph-sensor.c - Support for Atlas Scientific OEM pH-SM sensor * - * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2015-2018 Matt Ranostay + * Author: Matt Ranostay <matt.ranostay@konsulko.com> */ #include <linux/module.h> @@ -689,6 +681,6 @@ static struct i2c_driver atlas_driver = { }; module_i2c_driver(atlas_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("Atlas Scientific pH-SM sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c index 1ea9f5513b02..b4a46eb45789 100644 --- a/drivers/iio/chemical/ccs811.c +++ b/drivers/iio/chemical/ccs811.c @@ -32,7 +32,7 @@ #define CCS811_ALG_RESULT_DATA 0x02 #define CCS811_RAW_DATA 0x03 #define CCS811_HW_ID 0x20 -#define CCS881_HW_ID_VALUE 0x81 +#define CCS811_HW_ID_VALUE 0x81 #define CCS811_HW_VERSION 0x21 #define CCS811_HW_VERSION_VALUE 0x10 #define CCS811_HW_VERSION_MASK 0xF0 @@ -69,7 +69,7 @@ struct ccs811_reading { __be16 voc; u8 status; u8 error; - __be16 resistance; + __be16 raw_data; } __attribute__((__packed__)); struct ccs811_data { @@ -213,12 +213,12 @@ static int ccs811_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_VOLTAGE: - *val = be16_to_cpu(data->buffer.resistance) & + *val = be16_to_cpu(data->buffer.raw_data) & CCS811_VOLTAGE_MASK; ret = IIO_VAL_INT; break; case IIO_CURRENT: - *val = be16_to_cpu(data->buffer.resistance) >> 10; + *val = be16_to_cpu(data->buffer.raw_data) >> 10; ret = IIO_VAL_INT; break; case IIO_CONCENTRATION: @@ -356,7 +356,7 @@ static int ccs811_probe(struct i2c_client *client, if (ret < 0) return ret; - if (ret != CCS881_HW_ID_VALUE) { + if (ret != CCS811_HW_ID_VALUE) { dev_err(&client->dev, "hardware id doesn't match CCS81x\n"); return -ENODEV; } diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 9c9095ba4227..415b39339d4e 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * vz89x.c - Support for SGX Sensortech MiCS VZ89X VOC sensors * - * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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. - * + * Copyright (C) 2015-2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> */ #include <linux/module.h> @@ -419,6 +410,6 @@ static struct i2c_driver vz89x_driver = { }; module_i2c_driver(vz89x_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("SGX Sensortech MiCS VZ89X VOC sensors"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 7d30c59da3e2..705cb3e72663 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -289,6 +289,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids); static struct platform_driver cros_ec_sensors_platform_driver = { .driver = { .name = "cros-ec-sensors", + .pm = &cros_ec_sensors_pm_ops, }, .probe = cros_ec_sensors_probe, .id_table = cros_ec_sensors_ids, diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index 416cae5ebbd0..a620eb5ce202 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -446,5 +446,54 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, } EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write); +static int __maybe_unused cros_ec_sensors_prepare(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + + if (st->curr_sampl_freq == 0) + return 0; + + /* + * If the sensors are sampled at high frequency, we will not be able to + * sleep. Set sampling to a long period if necessary. + */ + if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) { + mutex_lock(&st->cmd_lock); + st->param.cmd = MOTIONSENSE_CMD_EC_RATE; + st->param.ec_rate.data = CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY; + cros_ec_motion_send_host_cmd(st, 0); + mutex_unlock(&st->cmd_lock); + } + return 0; +} + +static void __maybe_unused cros_ec_sensors_complete(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); + + if (st->curr_sampl_freq == 0) + return; + + if (st->curr_sampl_freq < CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY) { + mutex_lock(&st->cmd_lock); + st->param.cmd = MOTIONSENSE_CMD_EC_RATE; + st->param.ec_rate.data = st->curr_sampl_freq; + cros_ec_motion_send_host_cmd(st, 0); + mutex_unlock(&st->cmd_lock); + } +} + +const struct dev_pm_ops cros_ec_sensors_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .prepare = cros_ec_sensors_prepare, + .complete = cros_ec_sensors_complete +#endif +}; +EXPORT_SYMBOL_GPL(cros_ec_sensors_pm_ops); + MODULE_DESCRIPTION("ChromeOS EC sensor hub core functions"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h index 8bc2ca3c2e2e..2edf68dc7336 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h @@ -169,6 +169,8 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, struct iio_chan_spec const *chan, int val, int val2, long mask); +extern const struct dev_pm_ops cros_ec_sensors_pm_ops; + /* List of extended channel specification for all sensors */ extern const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[]; diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 845fd1c0fd9d..873c2bf637c0 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -158,7 +158,7 @@ static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan, long info) { switch (info) { - case 0: + case IIO_CHAN_INFO_RAW: return AD5380_REG_DATA(chan->address); case IIO_CHAN_INFO_CALIBBIAS: return AD5380_REG_OFFSET(chan->address); diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index 033f20eca616..9333177062c0 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -168,7 +168,7 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg, static int ad5764_chan_info_to_reg(struct iio_chan_spec const *chan, long info) { switch (info) { - case 0: + case IIO_CHAN_INFO_RAW: return AD5764_REG_DATA(chan->address); case IIO_CHAN_INFO_CALIBBIAS: return AD5764_REG_OFFSET(chan->address); diff --git a/drivers/iio/dummy/Kconfig b/drivers/iio/dummy/Kconfig index 5a29fbd3c531..c4fd108e91d3 100644 --- a/drivers/iio/dummy/Kconfig +++ b/drivers/iio/dummy/Kconfig @@ -9,20 +9,24 @@ config IIO_DUMMY_EVGEN tristate config IIO_SIMPLE_DUMMY - tristate "An example driver with no hardware requirements" - depends on IIO_SW_DEVICE - help - Driver intended mainly as documentation for how to write - a driver. May also be useful for testing userspace code - without hardware. + tristate "An example driver with no hardware requirements" + depends on IIO_SW_DEVICE + help + Driver intended mainly as documentation for how to write + a driver. May also be useful for testing userspace code + without hardware. if IIO_SIMPLE_DUMMY config IIO_SIMPLE_DUMMY_EVENTS - bool "Event generation support" - select IIO_DUMMY_EVGEN - help - Add some dummy events to the simple dummy driver. + bool "Event generation support" + select IIO_DUMMY_EVGEN + help + Add some dummy events to the simple dummy driver. + + The purpose of this is to generate 'fake' event interrupts thus + allowing that driver's code to be as close as possible to that + a normal driver talking to hardware. config IIO_SIMPLE_DUMMY_BUFFER bool "Buffered capture support" @@ -32,6 +36,9 @@ config IIO_SIMPLE_DUMMY_BUFFER help Add buffered data capture to the simple dummy driver. + Buffer handling elements of industrial I/O reference driver. + Uses the kfifo buffer. + endif # IIO_SIMPLE_DUMMY endmenu diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index f59995a90387..36941e69f959 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -115,7 +115,7 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = 0; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: hid_sensor_power_state(&gyro_state->common_attributes, true); report_id = gyro_state->gyro[chan->scan_index].report_id; address = gyro_3d_addresses[chan->scan_index]; diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 91aef5df24a1..84010501762d 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * max30100.c - Support for MAX30100 heart rate and pulse oximeter sensor * - * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2015, 2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> * * TODO: enable pulse length controls via device tree properties */ @@ -518,6 +510,6 @@ static struct i2c_driver max30100_driver = { }; module_i2c_driver(max30100_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("MAX30100 heart rate and pulse oximeter sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index 2c0fc9a400b8..1a0d458e4f4e 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -68,10 +68,12 @@ config HTS221 config HTS221_I2C tristate depends on HTS221 + select REGMAP_I2C config HTS221_SPI tristate depends on HTS221 + select REGMAP_SPI config HTU21 tristate "Measurement Specialties HTU21 humidity & temperature sensor" diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index df6bab40d6fa..1a9f8f4ffb88 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -159,7 +159,7 @@ static int dht11_decode(struct dht11 *dht11, int offset) } dht11->timestamp = ktime_get_boot_ns(); - if (hum_int < 20) { /* DHT22 */ + if (hum_int < 4) { /* DHT22: 100000 = (3*256+232)*100 */ dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * ((temp_int & 0x80) ? -100 : 100); dht11->humidity = ((hum_int << 8) + hum_dec) * 100; diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index d8438310b6d4..066e05f92081 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * hdc100x.c - Support for the TI HDC100x temperature + humidity sensors * - * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2015, 2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> * * Datasheets: * http://www.ti.com/product/HDC1000/datasheet @@ -449,6 +441,6 @@ static struct i2c_driver hdc100x_driver = { }; module_i2c_driver(hdc100x_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h index c581af8c0f5d..e41a3d83e95d 100644 --- a/drivers/iio/humidity/hts221.h +++ b/drivers/iio/humidity/hts221.h @@ -15,21 +15,8 @@ #include <linux/iio/iio.h> -#define HTS221_RX_MAX_LENGTH 8 -#define HTS221_TX_MAX_LENGTH 8 - #define HTS221_DATA_SIZE 2 -struct hts221_transfer_buffer { - u8 rx_buf[HTS221_RX_MAX_LENGTH]; - u8 tx_buf[HTS221_TX_MAX_LENGTH] ____cacheline_aligned; -}; - -struct hts221_transfer_function { - int (*read)(struct device *dev, u8 addr, int len, u8 *data); - int (*write)(struct device *dev, u8 addr, int len, u8 *data); -}; - enum hts221_sensor_type { HTS221_SENSOR_H, HTS221_SENSOR_T, @@ -44,8 +31,8 @@ struct hts221_sensor { struct hts221_hw { const char *name; struct device *dev; + struct regmap *regmap; - struct mutex lock; struct iio_trigger *trig; int irq; @@ -53,16 +40,12 @@ struct hts221_hw { bool enabled; u8 odr; - - const struct hts221_transfer_function *tf; - struct hts221_transfer_buffer tb; }; extern const struct dev_pm_ops hts221_pm_ops; -int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val); int hts221_probe(struct device *dev, int irq, const char *name, - const struct hts221_transfer_function *tf_ops); + struct regmap *regmap); int hts221_set_enable(struct hts221_hw *hw, bool enable); int hts221_allocate_buffers(struct hts221_hw *hw); int hts221_allocate_trigger(struct hts221_hw *hw); diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c index e971ea425268..1a94b0b91721 100644 --- a/drivers/iio/humidity/hts221_buffer.c +++ b/drivers/iio/humidity/hts221_buffer.c @@ -12,6 +12,8 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/irqreturn.h> +#include <linux/regmap.h> +#include <linux/bitfield.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> @@ -38,12 +40,10 @@ static int hts221_trig_set_state(struct iio_trigger *trig, bool state) { struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig); struct hts221_hw *hw = iio_priv(iio_dev); - int err; - - err = hts221_write_with_mask(hw, HTS221_REG_DRDY_EN_ADDR, - HTS221_REG_DRDY_EN_MASK, state); - return err < 0 ? err : 0; + return regmap_update_bits(hw->regmap, HTS221_REG_DRDY_EN_ADDR, + HTS221_REG_DRDY_EN_MASK, + FIELD_PREP(HTS221_REG_DRDY_EN_MASK, state)); } static const struct iio_trigger_ops hts221_trigger_ops = { @@ -53,15 +53,13 @@ static const struct iio_trigger_ops hts221_trigger_ops = { static irqreturn_t hts221_trigger_handler_thread(int irq, void *private) { struct hts221_hw *hw = private; - u8 status; - int err; + int err, status; - err = hw->tf->read(hw->dev, HTS221_REG_STATUS_ADDR, sizeof(status), - &status); + err = regmap_read(hw->regmap, HTS221_REG_STATUS_ADDR, &status); if (err < 0) return IRQ_HANDLED; - /* + /* * H_DA bit (humidity data available) is routed to DRDY line. * Humidity sample is computed after temperature one. * Here we can assume data channels are both available if H_DA bit @@ -102,8 +100,10 @@ int hts221_allocate_trigger(struct hts221_hw *hw) break; } - err = hts221_write_with_mask(hw, HTS221_REG_DRDY_HL_ADDR, - HTS221_REG_DRDY_HL_MASK, irq_active_low); + err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_HL_ADDR, + HTS221_REG_DRDY_HL_MASK, + FIELD_PREP(HTS221_REG_DRDY_HL_MASK, + irq_active_low)); if (err < 0) return err; @@ -114,9 +114,10 @@ int hts221_allocate_trigger(struct hts221_hw *hw) open_drain = true; } - err = hts221_write_with_mask(hw, HTS221_REG_DRDY_PP_OD_ADDR, - HTS221_REG_DRDY_PP_OD_MASK, - open_drain); + err = regmap_update_bits(hw->regmap, HTS221_REG_DRDY_PP_OD_ADDR, + HTS221_REG_DRDY_PP_OD_MASK, + FIELD_PREP(HTS221_REG_DRDY_PP_OD_MASK, + open_drain)); if (err < 0) return err; @@ -171,15 +172,15 @@ static irqreturn_t hts221_buffer_handler_thread(int irq, void *p) /* humidity data */ ch = &iio_dev->channels[HTS221_SENSOR_H]; - err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE, - buffer); + err = regmap_bulk_read(hw->regmap, ch->address, + buffer, HTS221_DATA_SIZE); if (err < 0) goto out; /* temperature data */ ch = &iio_dev->channels[HTS221_SENSOR_T]; - err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE, - buffer + HTS221_DATA_SIZE); + err = regmap_bulk_read(hw->regmap, ch->address, + buffer + HTS221_DATA_SIZE, HTS221_DATA_SIZE); if (err < 0) goto out; diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c index d3f7904766bd..166946d4978d 100644 --- a/drivers/iio/humidity/hts221_core.c +++ b/drivers/iio/humidity/hts221_core.c @@ -14,7 +14,8 @@ #include <linux/iio/sysfs.h> #include <linux/delay.h> #include <linux/pm.h> -#include <asm/unaligned.h> +#include <linux/regmap.h> +#include <linux/bitfield.h> #include "hts221.h" @@ -131,38 +132,11 @@ static const struct iio_chan_spec hts221_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(2), }; -int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val) -{ - u8 data; - int err; - - mutex_lock(&hw->lock); - - err = hw->tf->read(hw->dev, addr, sizeof(data), &data); - if (err < 0) { - dev_err(hw->dev, "failed to read %02x register\n", addr); - goto unlock; - } - - data = (data & ~mask) | ((val << __ffs(mask)) & mask); - - err = hw->tf->write(hw->dev, addr, sizeof(data), &data); - if (err < 0) - dev_err(hw->dev, "failed to write %02x register\n", addr); - -unlock: - mutex_unlock(&hw->lock); - - return err; -} - static int hts221_check_whoami(struct hts221_hw *hw) { - u8 data; - int err; + int err, data; - err = hw->tf->read(hw->dev, HTS221_REG_WHOAMI_ADDR, sizeof(data), - &data); + err = regmap_read(hw->regmap, HTS221_REG_WHOAMI_ADDR, &data); if (err < 0) { dev_err(hw->dev, "failed to read whoami register\n"); return err; @@ -188,8 +162,10 @@ static int hts221_update_odr(struct hts221_hw *hw, u8 odr) if (i == ARRAY_SIZE(hts221_odr_table)) return -EINVAL; - err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR, - HTS221_ODR_MASK, hts221_odr_table[i].val); + err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR, + HTS221_ODR_MASK, + FIELD_PREP(HTS221_ODR_MASK, + hts221_odr_table[i].val)); if (err < 0) return err; @@ -202,8 +178,8 @@ static int hts221_update_avg(struct hts221_hw *hw, enum hts221_sensor_type type, u16 val) { - int i, err; const struct hts221_avg *avg = &hts221_avg_list[type]; + int i, err, data; for (i = 0; i < HTS221_AVG_DEPTH; i++) if (avg->avg_avl[i] == val) @@ -212,7 +188,9 @@ static int hts221_update_avg(struct hts221_hw *hw, if (i == HTS221_AVG_DEPTH) return -EINVAL; - err = hts221_write_with_mask(hw, avg->addr, avg->mask, i); + data = ((i << __ffs(avg->mask)) & avg->mask); + err = regmap_update_bits(hw->regmap, avg->addr, + avg->mask, data); if (err < 0) return err; @@ -274,8 +252,9 @@ int hts221_set_enable(struct hts221_hw *hw, bool enable) { int err; - err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR, - HTS221_ENABLE_MASK, enable); + err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR, + HTS221_ENABLE_MASK, + FIELD_PREP(HTS221_ENABLE_MASK, enable)); if (err < 0) return err; @@ -286,38 +265,35 @@ int hts221_set_enable(struct hts221_hw *hw, bool enable) static int hts221_parse_temp_caldata(struct hts221_hw *hw) { - int err, *slope, *b_gen; + int err, *slope, *b_gen, cal0, cal1; s16 cal_x0, cal_x1, cal_y0, cal_y1; - u8 cal0, cal1; + __le16 val; - err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_Y_H, - sizeof(cal0), &cal0); + err = regmap_read(hw->regmap, HTS221_REG_0T_CAL_Y_H, &cal0); if (err < 0) return err; - err = hw->tf->read(hw->dev, HTS221_REG_T1_T0_CAL_Y_H, - sizeof(cal1), &cal1); + err = regmap_read(hw->regmap, HTS221_REG_T1_T0_CAL_Y_H, &cal1); if (err < 0) return err; - cal_y0 = (le16_to_cpu(cal1 & 0x3) << 8) | cal0; + cal_y0 = ((cal1 & 0x3) << 8) | cal0; - err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_Y_H, - sizeof(cal0), &cal0); + err = regmap_read(hw->regmap, HTS221_REG_1T_CAL_Y_H, &cal0); if (err < 0) return err; cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0; - err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_X_L, sizeof(cal_x0), - (u8 *)&cal_x0); + err = regmap_bulk_read(hw->regmap, HTS221_REG_0T_CAL_X_L, + &val, sizeof(val)); if (err < 0) return err; - cal_x0 = le16_to_cpu(cal_x0); + cal_x0 = le16_to_cpu(val); - err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_X_L, sizeof(cal_x1), - (u8 *)&cal_x1); + err = regmap_bulk_read(hw->regmap, HTS221_REG_1T_CAL_X_L, + &val, sizeof(val)); if (err < 0) return err; - cal_x1 = le16_to_cpu(cal_x1); + cal_x1 = le16_to_cpu(val); slope = &hw->sensors[HTS221_SENSOR_T].slope; b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen; @@ -332,33 +308,31 @@ static int hts221_parse_temp_caldata(struct hts221_hw *hw) static int hts221_parse_rh_caldata(struct hts221_hw *hw) { - int err, *slope, *b_gen; + int err, *slope, *b_gen, data; s16 cal_x0, cal_x1, cal_y0, cal_y1; - u8 data; + __le16 val; - err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_Y_H, sizeof(data), - &data); + err = regmap_read(hw->regmap, HTS221_REG_0RH_CAL_Y_H, &data); if (err < 0) return err; cal_y0 = data; - err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_Y_H, sizeof(data), - &data); + err = regmap_read(hw->regmap, HTS221_REG_1RH_CAL_Y_H, &data); if (err < 0) return err; cal_y1 = data; - err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_X_H, sizeof(cal_x0), - (u8 *)&cal_x0); + err = regmap_bulk_read(hw->regmap, HTS221_REG_0RH_CAL_X_H, + &val, sizeof(val)); if (err < 0) return err; - cal_x0 = le16_to_cpu(cal_x0); + cal_x0 = le16_to_cpu(val); - err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_X_H, sizeof(cal_x1), - (u8 *)&cal_x1); + err = regmap_bulk_read(hw->regmap, HTS221_REG_1RH_CAL_X_H, + &val, sizeof(val)); if (err < 0) return err; - cal_x1 = le16_to_cpu(cal_x1); + cal_x1 = le16_to_cpu(val); slope = &hw->sensors[HTS221_SENSOR_H].slope; b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen; @@ -431,7 +405,7 @@ static int hts221_get_sensor_offset(struct hts221_hw *hw, static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val) { - u8 data[HTS221_DATA_SIZE]; + __le16 data; int err; err = hts221_set_enable(hw, true); @@ -440,13 +414,13 @@ static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val) msleep(50); - err = hw->tf->read(hw->dev, addr, sizeof(data), data); + err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data)); if (err < 0) return err; hts221_set_enable(hw, false); - *val = (s16)get_unaligned_le16(data); + *val = (s16)le16_to_cpu(data); return IIO_VAL_INT; } @@ -582,7 +556,7 @@ static const struct iio_info hts221_info = { static const unsigned long hts221_scan_masks[] = {0x3, 0x0}; int hts221_probe(struct device *dev, int irq, const char *name, - const struct hts221_transfer_function *tf_ops) + struct regmap *regmap) { struct iio_dev *iio_dev; struct hts221_hw *hw; @@ -599,9 +573,7 @@ int hts221_probe(struct device *dev, int irq, const char *name, hw->name = name; hw->dev = dev; hw->irq = irq; - hw->tf = tf_ops; - - mutex_init(&hw->lock); + hw->regmap = regmap; err = hts221_check_whoami(hw); if (err < 0) @@ -616,8 +588,9 @@ int hts221_probe(struct device *dev, int irq, const char *name, iio_dev->info = &hts221_info; /* enable Block Data Update */ - err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR, - HTS221_BDU_MASK, 1); + err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR, + HTS221_BDU_MASK, + FIELD_PREP(HTS221_BDU_MASK, 1)); if (err < 0) return err; @@ -673,12 +646,10 @@ static int __maybe_unused hts221_suspend(struct device *dev) { struct iio_dev *iio_dev = dev_get_drvdata(dev); struct hts221_hw *hw = iio_priv(iio_dev); - int err; - err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR, - HTS221_ENABLE_MASK, false); - - return err < 0 ? err : 0; + return regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR, + HTS221_ENABLE_MASK, + FIELD_PREP(HTS221_ENABLE_MASK, false)); } static int __maybe_unused hts221_resume(struct device *dev) @@ -688,9 +659,10 @@ static int __maybe_unused hts221_resume(struct device *dev) int err = 0; if (hw->enabled) - err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR, - HTS221_ENABLE_MASK, true); - + err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR, + HTS221_ENABLE_MASK, + FIELD_PREP(HTS221_ENABLE_MASK, + true)); return err; } diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index 2c97350a0f76..b5b3f408a658 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -13,61 +13,33 @@ #include <linux/acpi.h> #include <linux/i2c.h> #include <linux/slab.h> -#include "hts221.h" - -#define I2C_AUTO_INCREMENT 0x80 - -static int hts221_i2c_read(struct device *dev, u8 addr, int len, u8 *data) -{ - struct i2c_msg msg[2]; - struct i2c_client *client = to_i2c_client(dev); - - if (len > 1) - addr |= I2C_AUTO_INCREMENT; - - msg[0].addr = client->addr; - msg[0].flags = client->flags; - msg[0].len = 1; - msg[0].buf = &addr; - - msg[1].addr = client->addr; - msg[1].flags = client->flags | I2C_M_RD; - msg[1].len = len; - msg[1].buf = data; - - return i2c_transfer(client->adapter, msg, 2); -} +#include <linux/regmap.h> -static int hts221_i2c_write(struct device *dev, u8 addr, int len, u8 *data) -{ - u8 send[len + 1]; - struct i2c_msg msg; - struct i2c_client *client = to_i2c_client(dev); - - if (len > 1) - addr |= I2C_AUTO_INCREMENT; - - send[0] = addr; - memcpy(&send[1], data, len * sizeof(u8)); - - msg.addr = client->addr; - msg.flags = client->flags; - msg.len = len + 1; - msg.buf = send; +#include "hts221.h" - return i2c_transfer(client->adapter, &msg, 1); -} +#define HTS221_I2C_AUTO_INCREMENT BIT(7) -static const struct hts221_transfer_function hts221_transfer_fn = { - .read = hts221_i2c_read, - .write = hts221_i2c_write, +static const struct regmap_config hts221_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = HTS221_I2C_AUTO_INCREMENT, + .read_flag_mask = HTS221_I2C_AUTO_INCREMENT, }; static int hts221_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &hts221_i2c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + return hts221_probe(&client->dev, client->irq, - client->name, &hts221_transfer_fn); + client->name, regmap); } static const struct acpi_device_id hts221_acpi_match[] = { diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c index 55b29b53b9d1..9c005f037026 100644 --- a/drivers/iio/humidity/hts221_spi.c +++ b/drivers/iio/humidity/hts221_spi.c @@ -12,76 +12,33 @@ #include <linux/module.h> #include <linux/spi/spi.h> #include <linux/slab.h> -#include "hts221.h" - -#define SENSORS_SPI_READ 0x80 -#define SPI_AUTO_INCREMENT 0x40 - -static int hts221_spi_read(struct device *dev, u8 addr, int len, u8 *data) -{ - int err; - struct spi_device *spi = to_spi_device(dev); - struct iio_dev *iio_dev = spi_get_drvdata(spi); - struct hts221_hw *hw = iio_priv(iio_dev); - - struct spi_transfer xfers[] = { - { - .tx_buf = hw->tb.tx_buf, - .bits_per_word = 8, - .len = 1, - }, - { - .rx_buf = hw->tb.rx_buf, - .bits_per_word = 8, - .len = len, - } - }; - - if (len > 1) - addr |= SPI_AUTO_INCREMENT; - hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ; - - err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); - if (err < 0) - return err; - - memcpy(data, hw->tb.rx_buf, len * sizeof(u8)); - - return len; -} - -static int hts221_spi_write(struct device *dev, u8 addr, int len, u8 *data) -{ - struct spi_device *spi = to_spi_device(dev); - struct iio_dev *iio_dev = spi_get_drvdata(spi); - struct hts221_hw *hw = iio_priv(iio_dev); - - struct spi_transfer xfers = { - .tx_buf = hw->tb.tx_buf, - .bits_per_word = 8, - .len = len + 1, - }; - - if (len >= HTS221_TX_MAX_LENGTH) - return -ENOMEM; +#include <linux/regmap.h> - if (len > 1) - addr |= SPI_AUTO_INCREMENT; - hw->tb.tx_buf[0] = addr; - memcpy(&hw->tb.tx_buf[1], data, len); +#include "hts221.h" - return spi_sync_transfer(spi, &xfers, 1); -} +#define HTS221_SPI_READ BIT(7) +#define HTS221_SPI_AUTO_INCREMENT BIT(6) -static const struct hts221_transfer_function hts221_transfer_fn = { - .read = hts221_spi_read, - .write = hts221_spi_write, +static const struct regmap_config hts221_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .write_flag_mask = HTS221_SPI_AUTO_INCREMENT, + .read_flag_mask = HTS221_SPI_READ | HTS221_SPI_AUTO_INCREMENT, }; static int hts221_spi_probe(struct spi_device *spi) { + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &hts221_spi_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to register spi regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + return hts221_probe(&spi->dev, spi->irq, - spi->modalias, &hts221_transfer_fn); + spi->modalias, regmap); } static const struct of_device_id hts221_spi_of_match[] = { diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 8fdd723afa05..a3cc7cd97026 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -27,7 +27,7 @@ enum st_lsm6dsx_hw_id { ST_LSM6DSX_MAX_ID, }; -#define ST_LSM6DSX_BUFF_SIZE 256 +#define ST_LSM6DSX_BUFF_SIZE 400 #define ST_LSM6DSX_CHAN_SIZE 2 #define ST_LSM6DSX_SAMPLE_SIZE 6 #define ST_LSM6DSX_MAX_WORD_LEN ((32 / ST_LSM6DSX_SAMPLE_SIZE) * \ @@ -58,12 +58,27 @@ struct st_lsm6dsx_fifo_ops { }; /** + * struct st_lsm6dsx_hw_ts_settings - ST IMU hw timer settings + * @timer_en: Hw timer enable register info (addr + mask). + * @hr_timer: Hw timer resolution register info (addr + mask). + * @fifo_en: Hw timer FIFO enable register info (addr + mask). + * @decimator: Hw timer FIFO decimator register info (addr + mask). + */ +struct st_lsm6dsx_hw_ts_settings { + struct st_lsm6dsx_reg timer_en; + struct st_lsm6dsx_reg hr_timer; + struct st_lsm6dsx_reg fifo_en; + struct st_lsm6dsx_reg decimator; +}; + +/** * struct st_lsm6dsx_settings - ST IMU sensor settings * @wai: Sensor WhoAmI default value. * @max_fifo_size: Sensor max fifo length in FIFO words. * @id: List of hw id supported by the driver configuration. * @decimator: List of decimator register info (addr + mask). * @fifo_ops: Sensor hw FIFO parameters. + * @ts_settings: Hw timer related settings. */ struct st_lsm6dsx_settings { u8 wai; @@ -71,6 +86,7 @@ struct st_lsm6dsx_settings { enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; struct st_lsm6dsx_fifo_ops fifo_ops; + struct st_lsm6dsx_hw_ts_settings ts_settings; }; enum st_lsm6dsx_sensor_id { @@ -94,8 +110,7 @@ enum st_lsm6dsx_fifo_mode { * @watermark: Sensor watermark level. * @sip: Number of samples in a given pattern. * @decimator: FIFO decimation factor. - * @delta_ts: Delta time between two consecutive interrupts. - * @ts: Latest timestamp from the interrupt handler. + * @ts_ref: Sensor timestamp reference for hw one. */ struct st_lsm6dsx_sensor { char name[32]; @@ -108,9 +123,7 @@ struct st_lsm6dsx_sensor { u16 watermark; u8 sip; u8 decimator; - - s64 delta_ts; - s64 ts; + s64 ts_ref; }; /** @@ -122,7 +135,8 @@ struct st_lsm6dsx_sensor { * @conf_lock: Mutex to prevent concurrent FIFO configuration update. * @fifo_mode: FIFO operating mode supported by the device. * @enable_mask: Enabled sensor bitmask. - * @sip: Total number of samples (acc/gyro) in a given pattern. + * @ts_sip: Total number of timestamp samples in a given pattern. + * @sip: Total number of samples (acc/gyro/ts) in a given pattern. * @buff: Device read buffer. * @iio_devs: Pointers to acc/gyro iio_dev instances. * @settings: Pointer to the specific sensor settings in use. @@ -137,6 +151,7 @@ struct st_lsm6dsx_hw { enum st_lsm6dsx_fifo_mode fifo_mode; u8 enable_mask; + u8 ts_sip; u8 sip; u8 *buff; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 1d6aa9b1a4cf..1045e025e92b 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -46,9 +46,13 @@ #define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3) #define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12) #define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e +#define ST_LSM6DSX_REG_TS_RESET_ADDR 0x42 #define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08 +#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */ +#define ST_LSM6DSX_TS_RESET_VAL 0xaa + struct st_lsm6dsx_decimator_entry { u8 decimator; u8 val; @@ -98,9 +102,10 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw, static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw) { + u16 max_odr, min_odr, sip = 0, ts_sip = 0; + const struct st_lsm6dsx_reg *ts_dec_reg; struct st_lsm6dsx_sensor *sensor; - u16 max_odr, min_odr, sip = 0; - int err, i; + int err = 0, i; u8 data; st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr); @@ -119,6 +124,7 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw) sensor->decimator = 0; data = 0; } + ts_sip = max_t(u16, ts_sip, sensor->sip); dec_reg = &hw->settings->decimator[sensor->id]; if (dec_reg->addr) { @@ -131,9 +137,23 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw) } sip += sensor->sip; } - hw->sip = sip; + hw->sip = sip + ts_sip; + hw->ts_sip = ts_sip; - return 0; + /* + * update hw ts decimator if necessary. Decimator for hw timestamp + * is always 1 or 0 in order to have a ts sample for each data + * sample in FIFO + */ + ts_dec_reg = &hw->settings->ts_settings.decimator; + if (ts_dec_reg->addr) { + int val, ts_dec = !!hw->ts_sip; + + val = ST_LSM6DSX_SHIFT_VAL(ts_dec, ts_dec_reg->mask); + err = regmap_update_bits(hw->regmap, ts_dec_reg->addr, + ts_dec_reg->mask, val); + } + return err; } int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, @@ -208,6 +228,28 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark) &wdata, sizeof(wdata)); } +static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw) +{ + struct st_lsm6dsx_sensor *sensor; + int i, err; + + /* reset hw ts counter */ + err = regmap_write(hw->regmap, ST_LSM6DSX_REG_TS_RESET_ADDR, + ST_LSM6DSX_TS_RESET_VAL); + if (err < 0) + return err; + + for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { + sensor = iio_priv(hw->iio_devs[i]); + /* + * store enable buffer timestamp as reference for + * hw timestamp + */ + sensor->ts_ref = iio_get_time_ns(hw->iio_devs[i]); + } + return 0; +} + /* * Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN in order to avoid * a kmalloc for each bus access @@ -231,6 +273,8 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data, return 0; } +#define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \ + sizeof(s64)) + sizeof(s64)) /** * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DS3H-LSM6DSL-LSM6DSM read FIFO routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. @@ -243,11 +287,13 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) { u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE; u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask; - int err, acc_sip, gyro_sip, read_len, samples, offset; + int err, acc_sip, gyro_sip, ts_sip, read_len, offset; struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor; - s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts; - u8 iio_buff[ALIGN(ST_LSM6DSX_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)]; + u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE]; + u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE]; + bool reset_ts = false; __le16 fifo_status; + s64 ts = 0; err = regmap_bulk_read(hw->regmap, hw->settings->fifo_ops.fifo_diff.addr, @@ -260,23 +306,10 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) * ST_LSM6DSX_CHAN_SIZE; - samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE; fifo_len = (fifo_len / pattern_len) * pattern_len; - /* - * compute delta timestamp between two consecutive samples - * in order to estimate queueing time of data generated - * by the sensor - */ acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); - acc_ts = acc_sensor->ts - acc_sensor->delta_ts; - acc_delta_ts = div_s64(acc_sensor->delta_ts * acc_sensor->decimator, - samples); - gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]); - gyro_ts = gyro_sensor->ts - gyro_sensor->delta_ts; - gyro_delta_ts = div_s64(gyro_sensor->delta_ts * gyro_sensor->decimator, - samples); for (read_len = 0; read_len < fifo_len; read_len += pattern_len) { err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len); @@ -287,7 +320,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) * Data are written to the FIFO with a specific pattern * depending on the configured ODRs. The first sequence of data * stored in FIFO contains the data of all enabled sensors - * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated + * (e.g. Gx, Gy, Gz, Ax, Ay, Az, Ts), then data are repeated * depending on the value of the decimation factor set for each * sensor. * @@ -296,35 +329,65 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) * - gyroscope ODR = 208Hz, accelerometer ODR = 104Hz * Since the gyroscope ODR is twice the accelerometer one, the * following pattern is repeated every 9 samples: - * - Gx, Gy, Gz, Ax, Ay, Az, Gx, Gy, Gz + * - Gx, Gy, Gz, Ax, Ay, Az, Ts, Gx, Gy, Gz, Ts, Gx, .. */ gyro_sip = gyro_sensor->sip; acc_sip = acc_sensor->sip; + ts_sip = hw->ts_sip; offset = 0; while (acc_sip > 0 || gyro_sip > 0) { - if (gyro_sip-- > 0) { - memcpy(iio_buff, &hw->buff[offset], + if (gyro_sip > 0) { + memcpy(gyro_buff, &hw->buff[offset], ST_LSM6DSX_SAMPLE_SIZE); - iio_push_to_buffers_with_timestamp( - hw->iio_devs[ST_LSM6DSX_ID_GYRO], - iio_buff, gyro_ts); offset += ST_LSM6DSX_SAMPLE_SIZE; - gyro_ts += gyro_delta_ts; } - - if (acc_sip-- > 0) { - memcpy(iio_buff, &hw->buff[offset], + if (acc_sip > 0) { + memcpy(acc_buff, &hw->buff[offset], ST_LSM6DSX_SAMPLE_SIZE); - iio_push_to_buffers_with_timestamp( - hw->iio_devs[ST_LSM6DSX_ID_ACC], - iio_buff, acc_ts); offset += ST_LSM6DSX_SAMPLE_SIZE; - acc_ts += acc_delta_ts; } + + if (ts_sip-- > 0) { + u8 data[ST_LSM6DSX_SAMPLE_SIZE]; + + memcpy(data, &hw->buff[offset], sizeof(data)); + /* + * hw timestamp is 3B long and it is stored + * in FIFO using 6B as 4th FIFO data set + * according to this schema: + * B0 = ts[15:8], B1 = ts[23:16], B3 = ts[7:0] + */ + ts = data[1] << 16 | data[0] << 8 | data[3]; + /* + * check if hw timestamp engine is going to + * reset (the sensor generates an interrupt + * to signal the hw timestamp will reset in + * 1.638s) + */ + if (!reset_ts && ts >= 0xff0000) + reset_ts = true; + ts *= ST_LSM6DSX_TS_SENSITIVITY; + + offset += ST_LSM6DSX_SAMPLE_SIZE; + } + + if (gyro_sip-- > 0) + iio_push_to_buffers_with_timestamp( + hw->iio_devs[ST_LSM6DSX_ID_GYRO], + gyro_buff, gyro_sensor->ts_ref + ts); + if (acc_sip-- > 0) + iio_push_to_buffers_with_timestamp( + hw->iio_devs[ST_LSM6DSX_ID_ACC], + acc_buff, acc_sensor->ts_ref + ts); } } + if (unlikely(reset_ts)) { + err = st_lsm6dsx_reset_hw_ts(hw); + if (err < 0) + return err; + } return read_len; } @@ -379,15 +442,12 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable) goto out; if (hw->enable_mask) { - err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); + /* reset hw ts counter */ + err = st_lsm6dsx_reset_hw_ts(hw); if (err < 0) goto out; - /* - * store enable buffer timestamp as reference to compute - * first delta timestamp - */ - sensor->ts = iio_get_time_ns(iio_dev); + err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); } out: @@ -399,25 +459,8 @@ out: static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private) { struct st_lsm6dsx_hw *hw = private; - struct st_lsm6dsx_sensor *sensor; - int i; - - if (!hw->sip) - return IRQ_NONE; - - for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { - sensor = iio_priv(hw->iio_devs[i]); - - if (sensor->sip > 0) { - s64 timestamp; - - timestamp = iio_get_time_ns(hw->iio_devs[i]); - sensor->delta_ts = timestamp - sensor->ts; - sensor->ts = timestamp; - } - } - return IRQ_WAKE_THREAD; + return hw->sip > 0 ? IRQ_WAKE_THREAD : IRQ_NONE; } static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index c2fa3239b9c6..8656d72ef4ee 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -181,6 +181,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .th_wl = 3, /* 1LSB = 2B */ }, + .ts_settings = { + .timer_en = { + .addr = 0x58, + .mask = BIT(7), + }, + .hr_timer = { + .addr = 0x5c, + .mask = BIT(4), + }, + .fifo_en = { + .addr = 0x07, + .mask = BIT(7), + }, + .decimator = { + .addr = 0x09, + .mask = GENMASK(5, 3), + }, + }, }, { .wai = 0x69, @@ -209,6 +227,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .th_wl = 3, /* 1LSB = 2B */ }, + .ts_settings = { + .timer_en = { + .addr = 0x58, + .mask = BIT(7), + }, + .hr_timer = { + .addr = 0x5c, + .mask = BIT(4), + }, + .fifo_en = { + .addr = 0x07, + .mask = BIT(7), + }, + .decimator = { + .addr = 0x09, + .mask = GENMASK(5, 3), + }, + }, }, { .wai = 0x6a, @@ -238,6 +274,24 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, .th_wl = 3, /* 1LSB = 2B */ }, + .ts_settings = { + .timer_en = { + .addr = 0x19, + .mask = BIT(5), + }, + .hr_timer = { + .addr = 0x5c, + .mask = BIT(4), + }, + .fifo_en = { + .addr = 0x07, + .mask = BIT(7), + }, + .decimator = { + .addr = 0x09, + .mask = GENMASK(5, 3), + }, + }, }, }; @@ -630,6 +684,44 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) return err; } +static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) +{ + const struct st_lsm6dsx_hw_ts_settings *ts_settings; + int err, val; + + ts_settings = &hw->settings->ts_settings; + /* enable hw timestamp generation if necessary */ + if (ts_settings->timer_en.addr) { + val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask); + err = regmap_update_bits(hw->regmap, + ts_settings->timer_en.addr, + ts_settings->timer_en.mask, val); + if (err < 0) + return err; + } + + /* enable high resolution for hw ts timer if necessary */ + if (ts_settings->hr_timer.addr) { + val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask); + err = regmap_update_bits(hw->regmap, + ts_settings->hr_timer.addr, + ts_settings->hr_timer.mask, val); + if (err < 0) + return err; + } + + /* enable ts queueing in FIFO if necessary */ + if (ts_settings->fifo_en.addr) { + val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask); + err = regmap_update_bits(hw->regmap, + ts_settings->fifo_en.addr, + ts_settings->fifo_en.mask, val); + if (err < 0) + return err; + } + return 0; +} + static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) { u8 drdy_int_reg; @@ -654,10 +746,14 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) if (err < 0) return err; - return regmap_update_bits(hw->regmap, drdy_int_reg, - ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, - FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, - 1)); + err = regmap_update_bits(hw->regmap, drdy_int_reg, + ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, + FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, + 1)); + if (err < 0) + return err; + + return st_lsm6dsx_init_hw_timer(hw); } static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 93fd421b10d7..074e50657366 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -275,6 +275,16 @@ config LTR501 This driver can also be built as a module. If so, the module will be called ltr501. +config LV0104CS + tristate "LV0104CS Ambient Light Sensor" + depends on I2C + help + Say Y here if you want to build support for the On Semiconductor + LV0104CS ambient light sensor. + + To compile this driver as a module, choose M here: + the module will be called lv0104cs. + config MAX44000 tristate "MAX44000 Ambient and Infrared Proximity Sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index f714067a7816..f1777036d4f8 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o +obj-$(CONFIG_LV0104CS) += lv0104cs.o obj-$(CONFIG_MAX44000) += max44000.o obj-$(CONFIG_OPT3001) += opt3001.o obj-$(CONFIG_PA12203001) += pa12203001.o diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index a8fa00e31c39..1f112ae15f3c 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor * - * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2015, 2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> * * TODO: gesture + proximity calib offsets */ @@ -1141,6 +1133,6 @@ static struct i2c_driver apds9960_driver = { }; module_i2c_driver(apds9960_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index acfad4aeb27a..8e8a0e7f78d1 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -276,6 +276,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids); static struct platform_driver cros_ec_light_prox_platform_driver = { .driver = { .name = "cros-ec-light-prox", + .pm = &cros_ec_sensors_pm_ops, }, .probe = cros_ec_light_prox_probe, .id_table = cros_ec_light_prox_ids, diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index befd693a4a31..406caaee9a3c 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -97,7 +97,7 @@ static int als_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = 0; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: switch (chan->scan_index) { case CHANNEL_SCAN_INDEX_INTENSITY: case CHANNEL_SCAN_INDEX_ILLUM: diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index 36208a3652e9..ff5a3324b489 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -199,7 +199,7 @@ static int lm3533_als_read_raw(struct iio_dev *indio_dev, int ret; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: switch (chan->type) { case IIO_LIGHT: ret = lm3533_als_get_adc(indio_dev, false, val); diff --git a/drivers/iio/light/lv0104cs.c b/drivers/iio/light/lv0104cs.c new file mode 100644 index 000000000000..55b8e2855647 --- /dev/null +++ b/drivers/iio/light/lv0104cs.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * lv0104cs.c: LV0104CS Ambient Light Sensor Driver + * + * Copyright (C) 2018 + * Author: Jeff LaBundy <jeff@labundy.com> + * + * 7-bit I2C slave address: 0x13 + * + * Link to data sheet: http://www.onsemi.com/pub/Collateral/LV0104CS-D.PDF + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define LV0104CS_REGVAL_MEASURE 0xE0 +#define LV0104CS_REGVAL_SLEEP 0x00 + +#define LV0104CS_SCALE_0_25X 0 +#define LV0104CS_SCALE_1X 1 +#define LV0104CS_SCALE_2X 2 +#define LV0104CS_SCALE_8X 3 +#define LV0104CS_SCALE_SHIFT 3 + +#define LV0104CS_INTEG_12_5MS 0 +#define LV0104CS_INTEG_100MS 1 +#define LV0104CS_INTEG_200MS 2 +#define LV0104CS_INTEG_SHIFT 1 + +#define LV0104CS_CALIBSCALE_UNITY 31 + +struct lv0104cs_private { + struct i2c_client *client; + struct mutex lock; + u8 calibscale; + u8 scale; + u8 int_time; +}; + +struct lv0104cs_mapping { + int val; + int val2; + u8 regval; +}; + +static const struct lv0104cs_mapping lv0104cs_calibscales[] = { + { 0, 666666, 0x81 }, + { 0, 800000, 0x82 }, + { 0, 857142, 0x83 }, + { 0, 888888, 0x84 }, + { 0, 909090, 0x85 }, + { 0, 923076, 0x86 }, + { 0, 933333, 0x87 }, + { 0, 941176, 0x88 }, + { 0, 947368, 0x89 }, + { 0, 952380, 0x8A }, + { 0, 956521, 0x8B }, + { 0, 960000, 0x8C }, + { 0, 962962, 0x8D }, + { 0, 965517, 0x8E }, + { 0, 967741, 0x8F }, + { 0, 969696, 0x90 }, + { 0, 971428, 0x91 }, + { 0, 972972, 0x92 }, + { 0, 974358, 0x93 }, + { 0, 975609, 0x94 }, + { 0, 976744, 0x95 }, + { 0, 977777, 0x96 }, + { 0, 978723, 0x97 }, + { 0, 979591, 0x98 }, + { 0, 980392, 0x99 }, + { 0, 981132, 0x9A }, + { 0, 981818, 0x9B }, + { 0, 982456, 0x9C }, + { 0, 983050, 0x9D }, + { 0, 983606, 0x9E }, + { 0, 984126, 0x9F }, + { 1, 0, 0x80 }, + { 1, 16129, 0xBF }, + { 1, 16666, 0xBE }, + { 1, 17241, 0xBD }, + { 1, 17857, 0xBC }, + { 1, 18518, 0xBB }, + { 1, 19230, 0xBA }, + { 1, 20000, 0xB9 }, + { 1, 20833, 0xB8 }, + { 1, 21739, 0xB7 }, + { 1, 22727, 0xB6 }, + { 1, 23809, 0xB5 }, + { 1, 24999, 0xB4 }, + { 1, 26315, 0xB3 }, + { 1, 27777, 0xB2 }, + { 1, 29411, 0xB1 }, + { 1, 31250, 0xB0 }, + { 1, 33333, 0xAF }, + { 1, 35714, 0xAE }, + { 1, 38461, 0xAD }, + { 1, 41666, 0xAC }, + { 1, 45454, 0xAB }, + { 1, 50000, 0xAA }, + { 1, 55555, 0xA9 }, + { 1, 62500, 0xA8 }, + { 1, 71428, 0xA7 }, + { 1, 83333, 0xA6 }, + { 1, 100000, 0xA5 }, + { 1, 125000, 0xA4 }, + { 1, 166666, 0xA3 }, + { 1, 250000, 0xA2 }, + { 1, 500000, 0xA1 }, +}; + +static const struct lv0104cs_mapping lv0104cs_scales[] = { + { 0, 250000, LV0104CS_SCALE_0_25X << LV0104CS_SCALE_SHIFT }, + { 1, 0, LV0104CS_SCALE_1X << LV0104CS_SCALE_SHIFT }, + { 2, 0, LV0104CS_SCALE_2X << LV0104CS_SCALE_SHIFT }, + { 8, 0, LV0104CS_SCALE_8X << LV0104CS_SCALE_SHIFT }, +}; + +static const struct lv0104cs_mapping lv0104cs_int_times[] = { + { 0, 12500, LV0104CS_INTEG_12_5MS << LV0104CS_INTEG_SHIFT }, + { 0, 100000, LV0104CS_INTEG_100MS << LV0104CS_INTEG_SHIFT }, + { 0, 200000, LV0104CS_INTEG_200MS << LV0104CS_INTEG_SHIFT }, +}; + +static int lv0104cs_write_reg(struct i2c_client *client, u8 regval) +{ + int ret; + + ret = i2c_master_send(client, (char *)®val, sizeof(regval)); + if (ret < 0) + return ret; + if (ret != sizeof(regval)) + return -EIO; + + return 0; +} + +static int lv0104cs_read_adc(struct i2c_client *client, u16 *adc_output) +{ + __be16 regval; + int ret; + + ret = i2c_master_recv(client, (char *)®val, sizeof(regval)); + if (ret < 0) + return ret; + if (ret != sizeof(regval)) + return -EIO; + + *adc_output = be16_to_cpu(regval); + + return 0; +} + +static int lv0104cs_get_lux(struct lv0104cs_private *lv0104cs, + int *val, int *val2) +{ + u8 regval = LV0104CS_REGVAL_MEASURE; + u16 adc_output; + int ret; + + regval |= lv0104cs_scales[lv0104cs->scale].regval; + regval |= lv0104cs_int_times[lv0104cs->int_time].regval; + ret = lv0104cs_write_reg(lv0104cs->client, regval); + if (ret) + return ret; + + /* wait for integration time to pass (with margin) */ + switch (lv0104cs->int_time) { + case LV0104CS_INTEG_12_5MS: + msleep(50); + break; + + case LV0104CS_INTEG_100MS: + msleep(150); + break; + + case LV0104CS_INTEG_200MS: + msleep(250); + break; + + default: + return -EINVAL; + } + + ret = lv0104cs_read_adc(lv0104cs->client, &adc_output); + if (ret) + return ret; + + ret = lv0104cs_write_reg(lv0104cs->client, LV0104CS_REGVAL_SLEEP); + if (ret) + return ret; + + /* convert ADC output to lux */ + switch (lv0104cs->scale) { + case LV0104CS_SCALE_0_25X: + *val = adc_output * 4; + *val2 = 0; + return 0; + + case LV0104CS_SCALE_1X: + *val = adc_output; + *val2 = 0; + return 0; + + case LV0104CS_SCALE_2X: + *val = adc_output / 2; + *val2 = (adc_output % 2) * 500000; + return 0; + + case LV0104CS_SCALE_8X: + *val = adc_output / 8; + *val2 = (adc_output % 8) * 125000; + return 0; + + default: + return -EINVAL; + } +} + +static int lv0104cs_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct lv0104cs_private *lv0104cs = iio_priv(indio_dev); + int ret; + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + mutex_lock(&lv0104cs->lock); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + ret = lv0104cs_get_lux(lv0104cs, val, val2); + if (ret) + goto err_mutex; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + + case IIO_CHAN_INFO_CALIBSCALE: + *val = lv0104cs_calibscales[lv0104cs->calibscale].val; + *val2 = lv0104cs_calibscales[lv0104cs->calibscale].val2; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + + case IIO_CHAN_INFO_SCALE: + *val = lv0104cs_scales[lv0104cs->scale].val; + *val2 = lv0104cs_scales[lv0104cs->scale].val2; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + + case IIO_CHAN_INFO_INT_TIME: + *val = lv0104cs_int_times[lv0104cs->int_time].val; + *val2 = lv0104cs_int_times[lv0104cs->int_time].val2; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + + default: + ret = -EINVAL; + } + +err_mutex: + mutex_unlock(&lv0104cs->lock); + + return ret; +} + +static int lv0104cs_set_calibscale(struct lv0104cs_private *lv0104cs, + int val, int val2) +{ + int calibscale = val * 1000000 + val2; + int floor, ceil, mid; + int ret, i, index; + + /* round to nearest quantized calibscale (sensitivity) */ + for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales) - 1; i++) { + floor = lv0104cs_calibscales[i].val * 1000000 + + lv0104cs_calibscales[i].val2; + ceil = lv0104cs_calibscales[i + 1].val * 1000000 + + lv0104cs_calibscales[i + 1].val2; + mid = (floor + ceil) / 2; + + /* round down */ + if (calibscale >= floor && calibscale < mid) { + index = i; + break; + } + + /* round up */ + if (calibscale >= mid && calibscale <= ceil) { + index = i + 1; + break; + } + } + + if (i == ARRAY_SIZE(lv0104cs_calibscales) - 1) + return -EINVAL; + + mutex_lock(&lv0104cs->lock); + + /* set calibscale (sensitivity) */ + ret = lv0104cs_write_reg(lv0104cs->client, + lv0104cs_calibscales[index].regval); + if (ret) + goto err_mutex; + + lv0104cs->calibscale = index; + +err_mutex: + mutex_unlock(&lv0104cs->lock); + + return ret; +} + +static int lv0104cs_set_scale(struct lv0104cs_private *lv0104cs, + int val, int val2) +{ + int i; + + /* hard matching */ + for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) { + if (val != lv0104cs_scales[i].val) + continue; + + if (val2 == lv0104cs_scales[i].val2) + break; + } + + if (i == ARRAY_SIZE(lv0104cs_scales)) + return -EINVAL; + + mutex_lock(&lv0104cs->lock); + lv0104cs->scale = i; + mutex_unlock(&lv0104cs->lock); + + return 0; +} + +static int lv0104cs_set_int_time(struct lv0104cs_private *lv0104cs, + int val, int val2) +{ + int i; + + /* hard matching */ + for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) { + if (val != lv0104cs_int_times[i].val) + continue; + + if (val2 == lv0104cs_int_times[i].val2) + break; + } + + if (i == ARRAY_SIZE(lv0104cs_int_times)) + return -EINVAL; + + mutex_lock(&lv0104cs->lock); + lv0104cs->int_time = i; + mutex_unlock(&lv0104cs->lock); + + return 0; +} + +static int lv0104cs_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct lv0104cs_private *lv0104cs = iio_priv(indio_dev); + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + return lv0104cs_set_calibscale(lv0104cs, val, val2); + + case IIO_CHAN_INFO_SCALE: + return lv0104cs_set_scale(lv0104cs, val, val2); + + case IIO_CHAN_INFO_INT_TIME: + return lv0104cs_set_int_time(lv0104cs, val, val2); + + default: + return -EINVAL; + } +} + +static ssize_t lv0104cs_show_calibscale_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales); i++) { + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", + lv0104cs_calibscales[i].val, + lv0104cs_calibscales[i].val2); + } + + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t lv0104cs_show_scale_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) { + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", + lv0104cs_scales[i].val, + lv0104cs_scales[i].val2); + } + + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t lv0104cs_show_int_time_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) { + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", + lv0104cs_int_times[i].val, + lv0104cs_int_times[i].val2); + } + + buf[len - 1] = '\n'; + + return len; +} + +static IIO_DEVICE_ATTR(calibscale_available, 0444, + lv0104cs_show_calibscale_avail, NULL, 0); +static IIO_DEVICE_ATTR(scale_available, 0444, + lv0104cs_show_scale_avail, NULL, 0); +static IIO_DEV_ATTR_INT_TIME_AVAIL(lv0104cs_show_int_time_avail); + +static struct attribute *lv0104cs_attributes[] = { + &iio_dev_attr_calibscale_available.dev_attr.attr, + &iio_dev_attr_scale_available.dev_attr.attr, + &iio_dev_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group lv0104cs_attribute_group = { + .attrs = lv0104cs_attributes, +}; + +static const struct iio_info lv0104cs_info = { + .attrs = &lv0104cs_attribute_group, + .read_raw = &lv0104cs_read_raw, + .write_raw = &lv0104cs_write_raw, +}; + +static const struct iio_chan_spec lv0104cs_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_INT_TIME), + }, +}; + +static int lv0104cs_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct lv0104cs_private *lv0104cs; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*lv0104cs)); + if (!indio_dev) + return -ENOMEM; + + lv0104cs = iio_priv(indio_dev); + + i2c_set_clientdata(client, lv0104cs); + lv0104cs->client = client; + + mutex_init(&lv0104cs->lock); + + lv0104cs->calibscale = LV0104CS_CALIBSCALE_UNITY; + lv0104cs->scale = LV0104CS_SCALE_1X; + lv0104cs->int_time = LV0104CS_INTEG_200MS; + + ret = lv0104cs_write_reg(lv0104cs->client, + lv0104cs_calibscales[LV0104CS_CALIBSCALE_UNITY].regval); + if (ret) + return ret; + + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->dev.parent = &client->dev; + indio_dev->channels = lv0104cs_channels; + indio_dev->num_channels = ARRAY_SIZE(lv0104cs_channels); + indio_dev->name = client->name; + indio_dev->info = &lv0104cs_info; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id lv0104cs_id[] = { + { "lv0104cs", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lv0104cs_id); + +static struct i2c_driver lv0104cs_i2c_driver = { + .driver = { + .name = "lv0104cs", + }, + .id_table = lv0104cs_id, + .probe = lv0104cs_probe, +}; +module_i2c_driver(lv0104cs_i2c_driver); + +MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); +MODULE_DESCRIPTION("LV0104CS Ambient Light Sensor Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index a1fd9d591818..d55c4885211a 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -167,7 +167,7 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = 0; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: hid_sensor_power_state(&magn_state->magn_flux_attributes, true); report_id = magn_state->magn[chan->address].report_id; diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 8bf282510be6..79ec2eba4969 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -5,6 +5,16 @@ menu "Digital potentiometers" +config AD5272 + tristate "Analog Devices AD5272 and similar Digital Potentiometer driver" + depends on I2C + help + Say yes here to build support for the Analog Devices AD5272 and AD5274 + digital potentiometer chip. + + To compile this driver as a module, choose M here: the + module will be called ad5272. + config DS1803 tristate "Maxim Integrated DS1803 Digital Potentiometer driver" depends on I2C @@ -37,6 +47,17 @@ config MAX5487 To compile this driver as a module, choose M here: the module will be called max5487. +config MCP4018 + tristate "Microchip MCP4017/18/19 Digital Potentiometer driver" + depends on I2C + help + Say yes here to build support for the Microchip + MCP4017, MCP4018, MCP4019 + digital potentiometer chips. + + To compile this driver as a module, choose M here: the + module will be called mcp4018. + config MCP4131 tristate "Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer driver" depends on SPI diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile index 1afd1e70f8cc..4af657883c3f 100644 --- a/drivers/iio/potentiometer/Makefile +++ b/drivers/iio/potentiometer/Makefile @@ -4,9 +4,11 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AD5272) += ad5272.o obj-$(CONFIG_DS1803) += ds1803.o obj-$(CONFIG_MAX5481) += max5481.o obj-$(CONFIG_MAX5487) += max5487.o +obj-$(CONFIG_MCP4018) += mcp4018.o obj-$(CONFIG_MCP4131) += mcp4131.o obj-$(CONFIG_MCP4531) += mcp4531.o obj-$(CONFIG_TPL0102) += tpl0102.o diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c new file mode 100644 index 000000000000..154f9a5da8bc --- /dev/null +++ b/drivers/iio/potentiometer/ad5272.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Analog Devices AD5272 digital potentiometer driver + * Copyright (C) 2018 Phil Reid <preid@electromag.com.au> + * + * Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/AD5272_5274.pdf + * + * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address + * ad5272 1 1024 20, 50, 100 01011xx + * ad5274 1 256 20, 100 01011xx + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/module.h> + +#define AD5272_RDAC_WR 1 +#define AD5272_RDAC_RD 2 +#define AD5272_RESET 4 +#define AD5272_CTL 7 + +#define AD5272_RDAC_WR_EN BIT(1) + +struct ad5272_cfg { + int max_pos; + int kohms; + int shift; +}; + +enum ad5272_type { + AD5272_020, + AD5272_050, + AD5272_100, + AD5274_020, + AD5274_100, +}; + +static const struct ad5272_cfg ad5272_cfg[] = { + [AD5272_020] = { .max_pos = 1024, .kohms = 20 }, + [AD5272_050] = { .max_pos = 1024, .kohms = 50 }, + [AD5272_100] = { .max_pos = 1024, .kohms = 100 }, + [AD5274_020] = { .max_pos = 256, .kohms = 20, .shift = 2 }, + [AD5274_100] = { .max_pos = 256, .kohms = 100, .shift = 2 }, +}; + +struct ad5272_data { + struct i2c_client *client; + struct mutex lock; + const struct ad5272_cfg *cfg; + u8 buf[2] ____cacheline_aligned; +}; + +static const struct iio_chan_spec ad5272_channel = { + .type = IIO_RESISTANCE, + .output = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +}; + +static int ad5272_write(struct ad5272_data *data, int reg, int val) +{ + int ret; + + data->buf[0] = (reg << 2) | ((val >> 8) & 0x3); + data->buf[1] = (u8)val; + + mutex_lock(&data->lock); + ret = i2c_master_send(data->client, data->buf, sizeof(data->buf)); + mutex_unlock(&data->lock); + return ret < 0 ? ret : 0; +} + +static int ad5272_read(struct ad5272_data *data, int reg, int *val) +{ + int ret; + + data->buf[0] = reg << 2; + data->buf[1] = 0; + + mutex_lock(&data->lock); + ret = i2c_master_send(data->client, data->buf, sizeof(data->buf)); + if (ret < 0) + goto error; + + ret = i2c_master_recv(data->client, data->buf, sizeof(data->buf)); + if (ret < 0) + goto error; + + *val = ((data->buf[0] & 0x3) << 8) | data->buf[1]; + ret = 0; +error: + mutex_unlock(&data->lock); + return ret; +} + +static int ad5272_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ad5272_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: { + ret = ad5272_read(data, AD5272_RDAC_RD, val); + *val = *val >> data->cfg->shift; + return ret ? ret : IIO_VAL_INT; + } + case IIO_CHAN_INFO_SCALE: + *val = 1000 * data->cfg->kohms; + *val2 = data->cfg->max_pos; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static int ad5272_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct ad5272_data *data = iio_priv(indio_dev); + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + if (val >= data->cfg->max_pos || val < 0 || val2) + return -EINVAL; + + return ad5272_write(data, AD5272_RDAC_WR, val << data->cfg->shift); +} + +static const struct iio_info ad5272_info = { + .read_raw = ad5272_read_raw, + .write_raw = ad5272_write_raw, +}; + +static int ad5272_reset(struct ad5272_data *data) +{ + struct gpio_desc *reset_gpio; + + reset_gpio = devm_gpiod_get_optional(&data->client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + + if (reset_gpio) { + udelay(1); + gpiod_set_value(reset_gpio, 1); + } else { + ad5272_write(data, AD5272_RESET, 0); + } + usleep_range(1000, 2000); + + return 0; +} + +static int ad5272_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct iio_dev *indio_dev; + struct ad5272_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, indio_dev); + + data = iio_priv(indio_dev); + data->client = client; + mutex_init(&data->lock); + data->cfg = &ad5272_cfg[id->driver_data]; + + ret = ad5272_reset(data); + if (ret) + return ret; + + ret = ad5272_write(data, AD5272_CTL, AD5272_RDAC_WR_EN); + if (ret < 0) + return -ENODEV; + + indio_dev->dev.parent = dev; + indio_dev->info = &ad5272_info; + indio_dev->channels = &ad5272_channel; + indio_dev->num_channels = 1; + indio_dev->name = client->name; + + return devm_iio_device_register(dev, indio_dev); +} + +#if defined(CONFIG_OF) +static const struct of_device_id ad5272_dt_ids[] = { + { .compatible = "adi,ad5272-020", .data = (void *)AD5272_020 }, + { .compatible = "adi,ad5272-050", .data = (void *)AD5272_050 }, + { .compatible = "adi,ad5272-100", .data = (void *)AD5272_100 }, + { .compatible = "adi,ad5274-020", .data = (void *)AD5274_020 }, + { .compatible = "adi,ad5274-100", .data = (void *)AD5274_100 }, + {} +}; +MODULE_DEVICE_TABLE(of, ad5272_dt_ids); +#endif /* CONFIG_OF */ + +static const struct i2c_device_id ad5272_id[] = { + { "ad5272-020", AD5272_020 }, + { "ad5272-050", AD5272_050 }, + { "ad5272-100", AD5272_100 }, + { "ad5274-020", AD5274_020 }, + { "ad5274-100", AD5274_100 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ad5272_id); + +static struct i2c_driver ad5272_driver = { + .driver = { + .name = "ad5272", + .of_match_table = of_match_ptr(ad5272_dt_ids), + }, + .probe = ad5272_probe, + .id_table = ad5272_id, +}; + +module_i2c_driver(ad5272_driver); + +MODULE_AUTHOR("Phil Reid <preid@eletromag.com.au>"); +MODULE_DESCRIPTION("AD5272 digital potentiometer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 9b0ff4ab2f9c..6bf12c9eccbd 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -64,7 +64,7 @@ static int ds1803_read_raw(struct iio_dev *indio_dev, struct ds1803_data *data = iio_priv(indio_dev); int pot = chan->channel; int ret; - u8 result[indio_dev->num_channels]; + u8 result[ARRAY_SIZE(ds1803_channels)]; switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c new file mode 100644 index 000000000000..601b25d1f387 --- /dev/null +++ b/drivers/iio/potentiometer/mcp4018.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Industrial I/O driver for Microchip digital potentiometers + * Copyright (c) 2018 Axentia Technologies AB + * Author: Peter Rosin <peda@axentia.se> + * + * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22147a.pdf + * + * DEVID #Wipers #Positions Resistor Opts (kOhm) + * mcp4017 1 128 5, 10, 50, 100 + * mcp4018 1 128 5, 10, 50, 100 + * mcp4019 1 128 5, 10, 50, 100 + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#define MCP4018_WIPER_MAX 127 + +struct mcp4018_cfg { + int kohms; +}; + +enum mcp4018_type { + MCP4018_502, + MCP4018_103, + MCP4018_503, + MCP4018_104, +}; + +static const struct mcp4018_cfg mcp4018_cfg[] = { + [MCP4018_502] = { .kohms = 5, }, + [MCP4018_103] = { .kohms = 10, }, + [MCP4018_503] = { .kohms = 50, }, + [MCP4018_104] = { .kohms = 100, }, +}; + +struct mcp4018_data { + struct i2c_client *client; + const struct mcp4018_cfg *cfg; +}; + +static const struct iio_chan_spec mcp4018_channel = { + .type = IIO_RESISTANCE, + .indexed = 1, + .output = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), +}; + +static int mcp4018_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mcp4018_data *data = iio_priv(indio_dev); + s32 ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_byte(data->client); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 1000 * data->cfg->kohms; + *val2 = MCP4018_WIPER_MAX; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static int mcp4018_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mcp4018_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (val > MCP4018_WIPER_MAX || val < 0) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return i2c_smbus_write_byte(data->client, val); +} + +static const struct iio_info mcp4018_info = { + .read_raw = mcp4018_read_raw, + .write_raw = mcp4018_write_raw, +}; + +#ifdef CONFIG_OF + +#define MCP4018_COMPATIBLE(of_compatible, cfg) { \ + .compatible = of_compatible, \ + .data = &mcp4018_cfg[cfg], \ +} + +static const struct of_device_id mcp4018_of_match[] = { + MCP4018_COMPATIBLE("microchip,mcp4017-502", MCP4018_502), + MCP4018_COMPATIBLE("microchip,mcp4017-103", MCP4018_103), + MCP4018_COMPATIBLE("microchip,mcp4017-503", MCP4018_503), + MCP4018_COMPATIBLE("microchip,mcp4017-104", MCP4018_104), + MCP4018_COMPATIBLE("microchip,mcp4018-502", MCP4018_502), + MCP4018_COMPATIBLE("microchip,mcp4018-103", MCP4018_103), + MCP4018_COMPATIBLE("microchip,mcp4018-503", MCP4018_503), + MCP4018_COMPATIBLE("microchip,mcp4018-104", MCP4018_104), + MCP4018_COMPATIBLE("microchip,mcp4019-502", MCP4018_502), + MCP4018_COMPATIBLE("microchip,mcp4019-103", MCP4018_103), + MCP4018_COMPATIBLE("microchip,mcp4019-503", MCP4018_503), + MCP4018_COMPATIBLE("microchip,mcp4019-104", MCP4018_104), + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mcp4018_of_match); + +#endif + +static int mcp4018_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct mcp4018_data *data; + struct iio_dev *indio_dev; + const struct of_device_id *match; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE)) { + dev_err(dev, "SMBUS Byte transfers not supported\n"); + return -EOPNOTSUPP; + } + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + match = of_match_device(of_match_ptr(mcp4018_of_match), dev); + if (match) + data->cfg = of_device_get_match_data(dev); + else + data->cfg = &mcp4018_cfg[id->driver_data]; + + indio_dev->dev.parent = dev; + indio_dev->info = &mcp4018_info; + indio_dev->channels = &mcp4018_channel; + indio_dev->num_channels = 1; + indio_dev->name = client->name; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct i2c_device_id mcp4018_id[] = { + { "mcp4017-502", MCP4018_502 }, + { "mcp4017-103", MCP4018_103 }, + { "mcp4017-503", MCP4018_503 }, + { "mcp4017-104", MCP4018_104 }, + { "mcp4018-502", MCP4018_502 }, + { "mcp4018-103", MCP4018_103 }, + { "mcp4018-503", MCP4018_503 }, + { "mcp4018-104", MCP4018_104 }, + { "mcp4019-502", MCP4018_502 }, + { "mcp4019-103", MCP4018_103 }, + { "mcp4019-503", MCP4018_503 }, + { "mcp4019-104", MCP4018_104 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, mcp4018_id); + +static struct i2c_driver mcp4018_driver = { + .driver = { + .name = "mcp4018", + .of_match_table = of_match_ptr(mcp4018_of_match), + }, + .probe = mcp4018_probe, + .id_table = mcp4018_id, +}; + +module_i2c_driver(mcp4018_driver); + +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); +MODULE_DESCRIPTION("MCP4018 digital potentiometer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/potentiometer/tpl0102.c b/drivers/iio/potentiometer/tpl0102.c index 93f9d4a8c9aa..ca1cce58fe20 100644 --- a/drivers/iio/potentiometer/tpl0102.c +++ b/drivers/iio/potentiometer/tpl0102.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * tpl0102.c - Support for Texas Instruments digital potentiometers * - * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2016, 2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> * * TODO: enable/disable hi-z output control */ @@ -156,6 +148,6 @@ static struct i2c_driver tpl0102_driver = { module_i2c_driver(tpl0102_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("TPL0102 digital potentiometer"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 007710991f15..85714055cc74 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * lmp91000.c - Support for Texas Instruments digital potentiostats * - * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2016, 2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> * * TODO: bias voltage + polarity control, and multiple chip support */ @@ -440,6 +432,6 @@ static struct i2c_driver lmp91000_driver = { }; module_i2c_driver(lmp91000_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("LMP91000 digital potentiostat"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h index ccda63c5b3c3..ead9e9f85894 100644 --- a/drivers/iio/pressure/ms5611.h +++ b/drivers/iio/pressure/ms5611.h @@ -63,7 +63,7 @@ struct ms5611_state { }; int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, - const char* name, int type); + const char *name, int type); int ms5611_remove(struct iio_dev *indio_dev); #endif /* _MS5611_H */ diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index b6249af48014..f130388a16a0 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * as3935.c - Support for AS3935 Franklin lightning sensor * - * Copyright (C) 2014 Matt Ranostay <mranostay@gmail.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. - * + * Copyright (C) 2014, 2017-2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> */ #include <linux/module.h> @@ -502,6 +493,6 @@ static struct spi_driver as3935_driver = { }; module_spi_driver(as3935_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("AS3935 lightning sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 4d56f67b24c6..47af54f14756 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * pulsedlight-lidar-lite-v2.c - Support for PulsedLight LIDAR sensor * - * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2015, 2017-2018 + * Author: Matt Ranostay <matt.ranostay@konsulko.com> * * TODO: interrupt mode, and signal strength reporting */ @@ -377,6 +369,6 @@ static struct i2c_driver lidar_driver = { }; module_i2c_driver(lidar_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("PulsedLight LIDAR sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index b8a2c2c8cac5..ff80409e0c44 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -32,9 +32,6 @@ #define SX9500_DRIVER_NAME "sx9500" #define SX9500_IRQ_NAME "sx9500_event" -#define SX9500_GPIO_INT "interrupt" -#define SX9500_GPIO_RESET "reset" - /* Register definitions. */ #define SX9500_REG_IRQ_SRC 0x00 #define SX9500_REG_STAT 0x01 @@ -866,26 +863,44 @@ static int sx9500_init_device(struct iio_dev *indio_dev) return sx9500_init_compensation(indio_dev); } +static const struct acpi_gpio_params reset_gpios = { 0, 0, false }; +static const struct acpi_gpio_params interrupt_gpios = { 2, 0, false }; + +static const struct acpi_gpio_mapping acpi_sx9500_gpios[] = { + { "reset-gpios", &reset_gpios, 1 }, + /* + * Some platforms have a bug in ACPI GPIO description making IRQ + * GPIO to be output only. Ask the GPIO core to ignore this limit. + */ + { "interrupt-gpios", &interrupt_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION }, + { }, +}; + static void sx9500_gpio_probe(struct i2c_client *client, struct sx9500_data *data) { struct gpio_desc *gpiod_int; struct device *dev; + int ret; if (!client) return; dev = &client->dev; + ret = devm_acpi_dev_add_driver_gpios(dev, acpi_sx9500_gpios); + if (ret) + dev_dbg(dev, "Unable to add GPIO mapping table\n"); + if (client->irq <= 0) { - gpiod_int = devm_gpiod_get(dev, SX9500_GPIO_INT, GPIOD_IN); + gpiod_int = devm_gpiod_get(dev, "interrupt", GPIOD_IN); if (IS_ERR(gpiod_int)) dev_err(dev, "gpio get irq failed\n"); else client->irq = gpiod_to_irq(gpiod_int); } - data->gpiod_rst = devm_gpiod_get(dev, SX9500_GPIO_RESET, GPIOD_OUT_HIGH); + data->gpiod_rst = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(data->gpiod_rst)) { dev_warn(dev, "gpio get reset pin failed\n"); data->gpiod_rst = NULL; diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index 5378976d6d27..82e4a62745e2 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -43,6 +43,18 @@ config MLX90614 This driver can also be built as a module. If so, the module will be called mlx90614. +config MLX90632 + tristate "MLX90632 contact-less infrared sensor with medical accuracy" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the Melexis + MLX90632 contact-less infrared sensor with medical accuracy + connected with I2C. + + This driver can also be built as a module. If so, the module will + be called mlx90632. + config TMP006 tristate "TMP006 infrared thermopile sensor" depends on I2C diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index 34bd9023727b..34a31db0bb63 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o obj-$(CONFIG_MLX90614) += mlx90614.o +obj-$(CONFIG_MLX90632) += mlx90632.o obj-$(CONFIG_TMP006) += tmp006.o obj-$(CONFIG_TMP007) += tmp007.o obj-$(CONFIG_TSYS01) += tsys01.o diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index e8b7e0b6c8ad..54e383231d1e 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * maxim_thermocouple.c - Support for Maxim thermocouple chips * - * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.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. + * Copyright (C) 2016-2018 Matt Ranostay + * Author: <matt.ranostay@konsulko.com> */ #include <linux/module.h> @@ -281,6 +273,6 @@ static struct spi_driver maxim_thermocouple_driver = { }; module_spi_driver(maxim_thermocouple_driver); -MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>"); MODULE_DESCRIPTION("Maxim thermocouple sensors"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c new file mode 100644 index 000000000000..9851311aa3fd --- /dev/null +++ b/drivers/iio/temperature/mlx90632.c @@ -0,0 +1,752 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mlx90632.c - Melexis MLX90632 contactless IR temperature sensor + * + * Copyright (c) 2017 Melexis <cmo@melexis.com> + * + * Driver for the Melexis MLX90632 I2C 16-bit IR thermopile sensor + */ +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/math64.h> +#include <linux/of.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +/* Memory sections addresses */ +#define MLX90632_ADDR_RAM 0x4000 /* Start address of ram */ +#define MLX90632_ADDR_EEPROM 0x2480 /* Start address of user eeprom */ + +/* EEPROM addresses - used at startup */ +#define MLX90632_EE_CTRL 0x24d4 /* Control register initial value */ +#define MLX90632_EE_I2C_ADDR 0x24d5 /* I2C address register initial value */ +#define MLX90632_EE_VERSION 0x240b /* EEPROM version reg address */ +#define MLX90632_EE_P_R 0x240c /* P_R calibration register 32bit */ +#define MLX90632_EE_P_G 0x240e /* P_G calibration register 32bit */ +#define MLX90632_EE_P_T 0x2410 /* P_T calibration register 32bit */ +#define MLX90632_EE_P_O 0x2412 /* P_O calibration register 32bit */ +#define MLX90632_EE_Aa 0x2414 /* Aa calibration register 32bit */ +#define MLX90632_EE_Ab 0x2416 /* Ab calibration register 32bit */ +#define MLX90632_EE_Ba 0x2418 /* Ba calibration register 32bit */ +#define MLX90632_EE_Bb 0x241a /* Bb calibration register 32bit */ +#define MLX90632_EE_Ca 0x241c /* Ca calibration register 32bit */ +#define MLX90632_EE_Cb 0x241e /* Cb calibration register 32bit */ +#define MLX90632_EE_Da 0x2420 /* Da calibration register 32bit */ +#define MLX90632_EE_Db 0x2422 /* Db calibration register 32bit */ +#define MLX90632_EE_Ea 0x2424 /* Ea calibration register 32bit */ +#define MLX90632_EE_Eb 0x2426 /* Eb calibration register 32bit */ +#define MLX90632_EE_Fa 0x2428 /* Fa calibration register 32bit */ +#define MLX90632_EE_Fb 0x242a /* Fb calibration register 32bit */ +#define MLX90632_EE_Ga 0x242c /* Ga calibration register 32bit */ + +#define MLX90632_EE_Gb 0x242e /* Gb calibration register 16bit */ +#define MLX90632_EE_Ka 0x242f /* Ka calibration register 16bit */ + +#define MLX90632_EE_Ha 0x2481 /* Ha customer calib value reg 16bit */ +#define MLX90632_EE_Hb 0x2482 /* Hb customer calib value reg 16bit */ + +/* Register addresses - volatile */ +#define MLX90632_REG_I2C_ADDR 0x3000 /* Chip I2C address register */ + +/* Control register address - volatile */ +#define MLX90632_REG_CONTROL 0x3001 /* Control Register address */ +#define MLX90632_CFG_PWR_MASK GENMASK(2, 1) /* PowerMode Mask */ +/* PowerModes statuses */ +#define MLX90632_PWR_STATUS(ctrl_val) (ctrl_val << 1) +#define MLX90632_PWR_STATUS_HALT MLX90632_PWR_STATUS(0) /* hold */ +#define MLX90632_PWR_STATUS_SLEEP_STEP MLX90632_PWR_STATUS(1) /* sleep step*/ +#define MLX90632_PWR_STATUS_STEP MLX90632_PWR_STATUS(2) /* step */ +#define MLX90632_PWR_STATUS_CONTINUOUS MLX90632_PWR_STATUS(3) /* continuous*/ + +/* Device status register - volatile */ +#define MLX90632_REG_STATUS 0x3fff /* Device status register */ +#define MLX90632_STAT_BUSY BIT(10) /* Device busy indicator */ +#define MLX90632_STAT_EE_BUSY BIT(9) /* EEPROM busy indicator */ +#define MLX90632_STAT_BRST BIT(8) /* Brown out reset indicator */ +#define MLX90632_STAT_CYCLE_POS GENMASK(6, 2) /* Data position */ +#define MLX90632_STAT_DATA_RDY BIT(0) /* Data ready indicator */ + +/* RAM_MEAS address-es for each channel */ +#define MLX90632_RAM_1(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num) +#define MLX90632_RAM_2(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 1) +#define MLX90632_RAM_3(meas_num) (MLX90632_ADDR_RAM + 3 * meas_num + 2) + +/* Magic constants */ +#define MLX90632_ID_MEDICAL 0x0105 /* EEPROM DSPv5 Medical device id */ +#define MLX90632_ID_CONSUMER 0x0205 /* EEPROM DSPv5 Consumer device id */ +#define MLX90632_RESET_CMD 0x0006 /* Reset sensor (address or global) */ +#define MLX90632_REF_12 12LL /**< ResCtrlRef value of Ch 1 or Ch 2 */ +#define MLX90632_REF_3 12LL /**< ResCtrlRef value of Channel 3 */ +#define MLX90632_MAX_MEAS_NUM 31 /**< Maximum measurements in list */ +#define MLX90632_SLEEP_DELAY_MS 3000 /**< Autosleep delay */ + +struct mlx90632_data { + struct i2c_client *client; + struct mutex lock; /* Multiple reads for single measurement */ + struct regmap *regmap; + u16 emissivity; +}; + +static const struct regmap_range mlx90632_volatile_reg_range[] = { + regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL), + regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS), + regmap_reg_range(MLX90632_RAM_1(0), + MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), +}; + +static const struct regmap_access_table mlx90632_volatile_regs_tbl = { + .yes_ranges = mlx90632_volatile_reg_range, + .n_yes_ranges = ARRAY_SIZE(mlx90632_volatile_reg_range), +}; + +static const struct regmap_range mlx90632_read_reg_range[] = { + regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka), + regmap_reg_range(MLX90632_EE_CTRL, MLX90632_EE_I2C_ADDR), + regmap_reg_range(MLX90632_EE_Ha, MLX90632_EE_Hb), + regmap_reg_range(MLX90632_REG_I2C_ADDR, MLX90632_REG_CONTROL), + regmap_reg_range(MLX90632_REG_STATUS, MLX90632_REG_STATUS), + regmap_reg_range(MLX90632_RAM_1(0), + MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), +}; + +static const struct regmap_access_table mlx90632_readable_regs_tbl = { + .yes_ranges = mlx90632_read_reg_range, + .n_yes_ranges = ARRAY_SIZE(mlx90632_read_reg_range), +}; + +static const struct regmap_range mlx90632_no_write_reg_range[] = { + regmap_reg_range(MLX90632_EE_VERSION, MLX90632_EE_Ka), + regmap_reg_range(MLX90632_RAM_1(0), + MLX90632_RAM_3(MLX90632_MAX_MEAS_NUM)), +}; + +static const struct regmap_access_table mlx90632_writeable_regs_tbl = { + .no_ranges = mlx90632_no_write_reg_range, + .n_no_ranges = ARRAY_SIZE(mlx90632_no_write_reg_range), +}; + +static const struct regmap_config mlx90632_regmap = { + .reg_bits = 16, + .val_bits = 16, + + .volatile_table = &mlx90632_volatile_regs_tbl, + .rd_table = &mlx90632_readable_regs_tbl, + .wr_table = &mlx90632_writeable_regs_tbl, + + .use_single_rw = true, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .cache_type = REGCACHE_RBTREE, +}; + +static s32 mlx90632_pwr_set_sleep_step(struct regmap *regmap) +{ + return regmap_update_bits(regmap, MLX90632_REG_CONTROL, + MLX90632_CFG_PWR_MASK, + MLX90632_PWR_STATUS_SLEEP_STEP); +} + +static s32 mlx90632_pwr_continuous(struct regmap *regmap) +{ + return regmap_update_bits(regmap, MLX90632_REG_CONTROL, + MLX90632_CFG_PWR_MASK, + MLX90632_PWR_STATUS_CONTINUOUS); +} + +/** + * mlx90632_perform_measurement - Trigger and retrieve current measurement cycle + * @*data: pointer to mlx90632_data object containing regmap information + * + * Perform a measurement and return latest measurement cycle position reported + * by sensor. This is a blocking function for 500ms, as that is default sensor + * refresh rate. + */ +static int mlx90632_perform_measurement(struct mlx90632_data *data) +{ + int ret, tries = 100; + unsigned int reg_status; + + ret = regmap_update_bits(data->regmap, MLX90632_REG_STATUS, + MLX90632_STAT_DATA_RDY, 0); + if (ret < 0) + return ret; + + while (tries-- > 0) { + ret = regmap_read(data->regmap, MLX90632_REG_STATUS, + ®_status); + if (ret < 0) + return ret; + if (reg_status & MLX90632_STAT_DATA_RDY) + break; + usleep_range(10000, 11000); + } + + if (tries < 0) { + dev_err(&data->client->dev, "data not ready"); + return -ETIMEDOUT; + } + + return (reg_status & MLX90632_STAT_CYCLE_POS) >> 2; +} + +static int mlx90632_channel_new_select(int perform_ret, uint8_t *channel_new, + uint8_t *channel_old) +{ + switch (perform_ret) { + case 1: + *channel_new = 1; + *channel_old = 2; + break; + case 2: + *channel_new = 2; + *channel_old = 1; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mlx90632_read_ambient_raw(struct regmap *regmap, + s16 *ambient_new_raw, s16 *ambient_old_raw) +{ + int ret; + unsigned int read_tmp; + + ret = regmap_read(regmap, MLX90632_RAM_3(1), &read_tmp); + if (ret < 0) + return ret; + *ambient_new_raw = (s16)read_tmp; + + ret = regmap_read(regmap, MLX90632_RAM_3(2), &read_tmp); + if (ret < 0) + return ret; + *ambient_old_raw = (s16)read_tmp; + + return ret; +} + +static int mlx90632_read_object_raw(struct regmap *regmap, + int perform_measurement_ret, + s16 *object_new_raw, s16 *object_old_raw) +{ + int ret; + unsigned int read_tmp; + s16 read; + u8 channel = 0; + u8 channel_old = 0; + + ret = mlx90632_channel_new_select(perform_measurement_ret, &channel, + &channel_old); + if (ret != 0) + return ret; + + ret = regmap_read(regmap, MLX90632_RAM_2(channel), &read_tmp); + if (ret < 0) + return ret; + + read = (s16)read_tmp; + + ret = regmap_read(regmap, MLX90632_RAM_1(channel), &read_tmp); + if (ret < 0) + return ret; + *object_new_raw = (read + (s16)read_tmp) / 2; + + ret = regmap_read(regmap, MLX90632_RAM_2(channel_old), &read_tmp); + if (ret < 0) + return ret; + read = (s16)read_tmp; + + ret = regmap_read(regmap, MLX90632_RAM_1(channel_old), &read_tmp); + if (ret < 0) + return ret; + *object_old_raw = (read + (s16)read_tmp) / 2; + + return ret; +} + +static int mlx90632_read_all_channel(struct mlx90632_data *data, + s16 *ambient_new_raw, s16 *ambient_old_raw, + s16 *object_new_raw, s16 *object_old_raw) +{ + s32 ret, measurement; + + mutex_lock(&data->lock); + measurement = mlx90632_perform_measurement(data); + if (measurement < 0) { + ret = measurement; + goto read_unlock; + } + ret = mlx90632_read_ambient_raw(data->regmap, ambient_new_raw, + ambient_old_raw); + if (ret < 0) + goto read_unlock; + + ret = mlx90632_read_object_raw(data->regmap, measurement, + object_new_raw, object_old_raw); +read_unlock: + mutex_unlock(&data->lock); + return ret; +} + +static int mlx90632_read_ee_register(struct regmap *regmap, u16 reg_lsb, + s32 *reg_value) +{ + s32 ret; + unsigned int read; + u32 value; + + ret = regmap_read(regmap, reg_lsb, &read); + if (ret < 0) + return ret; + + value = read; + + ret = regmap_read(regmap, reg_lsb + 1, &read); + if (ret < 0) + return ret; + + *reg_value = (read << 16) | (value & 0xffff); + + return 0; +} + +static s64 mlx90632_preprocess_temp_amb(s16 ambient_new_raw, + s16 ambient_old_raw, s16 Gb) +{ + s64 VR_Ta, kGb, tmp; + + kGb = ((s64)Gb * 1000LL) >> 10ULL; + VR_Ta = (s64)ambient_old_raw * 1000000LL + + kGb * div64_s64(((s64)ambient_new_raw * 1000LL), + (MLX90632_REF_3)); + tmp = div64_s64( + div64_s64(((s64)ambient_new_raw * 1000000000000LL), + (MLX90632_REF_3)), VR_Ta); + return div64_s64(tmp << 19ULL, 1000LL); +} + +static s64 mlx90632_preprocess_temp_obj(s16 object_new_raw, s16 object_old_raw, + s16 ambient_new_raw, + s16 ambient_old_raw, s16 Ka) +{ + s64 VR_IR, kKa, tmp; + + kKa = ((s64)Ka * 1000LL) >> 10ULL; + VR_IR = (s64)ambient_old_raw * 1000000LL + + kKa * div64_s64(((s64)ambient_new_raw * 1000LL), + (MLX90632_REF_3)); + tmp = div64_s64( + div64_s64(((s64)((object_new_raw + object_old_raw) / 2) + * 1000000000000LL), (MLX90632_REF_12)), + VR_IR); + return div64_s64((tmp << 19ULL), 1000LL); +} + +static s32 mlx90632_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw, + s32 P_T, s32 P_R, s32 P_G, s32 P_O, + s16 Gb) +{ + s64 Asub, Bsub, Ablock, Bblock, Cblock, AMB, sum; + + AMB = mlx90632_preprocess_temp_amb(ambient_new_raw, ambient_old_raw, + Gb); + Asub = ((s64)P_T * 10000000000LL) >> 44ULL; + Bsub = AMB - (((s64)P_R * 1000LL) >> 8ULL); + Ablock = Asub * (Bsub * Bsub); + Bblock = (div64_s64(Bsub * 10000000LL, P_G)) << 20ULL; + Cblock = ((s64)P_O * 10000000000LL) >> 8ULL; + + sum = div64_s64(Ablock, 1000000LL) + Bblock + Cblock; + + return div64_s64(sum, 10000000LL); +} + +static s32 mlx90632_calc_temp_object_iteration(s32 prev_object_temp, s64 object, + s64 TAdut, s32 Fa, s32 Fb, + s32 Ga, s16 Ha, s16 Hb, + u16 emissivity) +{ + s64 calcedKsTO, calcedKsTA, ir_Alpha, TAdut4, Alpha_corr; + s64 Ha_customer, Hb_customer; + + Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL; + Hb_customer = ((s64)Hb * 100) >> 10ULL; + + calcedKsTO = ((s64)((s64)Ga * (prev_object_temp - 25 * 1000LL) + * 1000LL)) >> 36LL; + calcedKsTA = ((s64)(Fb * (TAdut - 25 * 1000000LL))) >> 36LL; + Alpha_corr = div64_s64((((s64)(Fa * 10000000000LL) >> 46LL) + * Ha_customer), 1000LL); + Alpha_corr *= ((s64)(1 * 1000000LL + calcedKsTO + calcedKsTA)); + Alpha_corr = emissivity * div64_s64(Alpha_corr, 100000LL); + Alpha_corr = div64_s64(Alpha_corr, 1000LL); + ir_Alpha = div64_s64((s64)object * 10000000LL, Alpha_corr); + TAdut4 = (div64_s64(TAdut, 10000LL) + 27315) * + (div64_s64(TAdut, 10000LL) + 27315) * + (div64_s64(TAdut, 10000LL) + 27315) * + (div64_s64(TAdut, 10000LL) + 27315); + + return (int_sqrt64(int_sqrt64(ir_Alpha * 1000000000000LL + TAdut4)) + - 27315 - Hb_customer) * 10; +} + +static s32 mlx90632_calc_temp_object(s64 object, s64 ambient, s32 Ea, s32 Eb, + s32 Fa, s32 Fb, s32 Ga, s16 Ha, s16 Hb, + u16 tmp_emi) +{ + s64 kTA, kTA0, TAdut; + s64 temp = 25000; + s8 i; + + kTA = (Ea * 1000LL) >> 16LL; + kTA0 = (Eb * 1000LL) >> 8LL; + TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 25 * 1000000LL; + + /* Iterations of calculation as described in datasheet */ + for (i = 0; i < 5; ++i) { + temp = mlx90632_calc_temp_object_iteration(temp, object, TAdut, + Fa, Fb, Ga, Ha, Hb, + tmp_emi); + } + return temp; +} + +static int mlx90632_calc_object_dsp105(struct mlx90632_data *data, int *val) +{ + s32 ret; + s32 Ea, Eb, Fa, Fb, Ga; + unsigned int read_tmp; + s16 Ha, Hb, Gb, Ka; + s16 ambient_new_raw, ambient_old_raw, object_new_raw, object_old_raw; + s64 object, ambient; + + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ea, &Ea); + if (ret < 0) + return ret; + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Eb, &Eb); + if (ret < 0) + return ret; + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fa, &Fa); + if (ret < 0) + return ret; + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Fb, &Fb); + if (ret < 0) + return ret; + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_Ga, &Ga); + if (ret < 0) + return ret; + ret = regmap_read(data->regmap, MLX90632_EE_Ha, &read_tmp); + if (ret < 0) + return ret; + Ha = (s16)read_tmp; + ret = regmap_read(data->regmap, MLX90632_EE_Hb, &read_tmp); + if (ret < 0) + return ret; + Hb = (s16)read_tmp; + ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp); + if (ret < 0) + return ret; + Gb = (s16)read_tmp; + ret = regmap_read(data->regmap, MLX90632_EE_Ka, &read_tmp); + if (ret < 0) + return ret; + Ka = (s16)read_tmp; + + ret = mlx90632_read_all_channel(data, + &ambient_new_raw, &ambient_old_raw, + &object_new_raw, &object_old_raw); + if (ret < 0) + return ret; + + ambient = mlx90632_preprocess_temp_amb(ambient_new_raw, + ambient_old_raw, Gb); + object = mlx90632_preprocess_temp_obj(object_new_raw, + object_old_raw, + ambient_new_raw, + ambient_old_raw, Ka); + + *val = mlx90632_calc_temp_object(object, ambient, Ea, Eb, Fa, Fb, Ga, + Ha, Hb, data->emissivity); + return 0; +} + +static int mlx90632_calc_ambient_dsp105(struct mlx90632_data *data, int *val) +{ + s32 ret; + unsigned int read_tmp; + s32 PT, PR, PG, PO; + s16 Gb; + s16 ambient_new_raw, ambient_old_raw; + + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_R, &PR); + if (ret < 0) + return ret; + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_G, &PG); + if (ret < 0) + return ret; + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_T, &PT); + if (ret < 0) + return ret; + ret = mlx90632_read_ee_register(data->regmap, MLX90632_EE_P_O, &PO); + if (ret < 0) + return ret; + ret = regmap_read(data->regmap, MLX90632_EE_Gb, &read_tmp); + if (ret < 0) + return ret; + Gb = (s16)read_tmp; + + ret = mlx90632_read_ambient_raw(data->regmap, &ambient_new_raw, + &ambient_old_raw); + if (ret < 0) + return ret; + *val = mlx90632_calc_temp_ambient(ambient_new_raw, ambient_old_raw, + PT, PR, PG, PO, Gb); + return ret; +} + +static int mlx90632_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct mlx90632_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (channel->channel2) { + case IIO_MOD_TEMP_AMBIENT: + ret = mlx90632_calc_ambient_dsp105(data, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; + case IIO_MOD_TEMP_OBJECT: + ret = mlx90632_calc_object_dsp105(data, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_CALIBEMISSIVITY: + if (data->emissivity == 1000) { + *val = 1; + *val2 = 0; + } else { + *val = 0; + *val2 = data->emissivity * 1000; + } + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +static int mlx90632_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int val, + int val2, long mask) +{ + struct mlx90632_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_CALIBEMISSIVITY: + /* Confirm we are within 0 and 1.0 */ + if (val < 0 || val2 < 0 || val > 1 || + (val == 1 && val2 != 0)) + return -EINVAL; + data->emissivity = val * 1000 + val2 / 1000; + return 0; + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec mlx90632_channels[] = { + { + .type = IIO_TEMP, + .modified = 1, + .channel2 = IIO_MOD_TEMP_AMBIENT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, + { + .type = IIO_TEMP, + .modified = 1, + .channel2 = IIO_MOD_TEMP_OBJECT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_CALIBEMISSIVITY), + }, +}; + +static const struct iio_info mlx90632_info = { + .read_raw = mlx90632_read_raw, + .write_raw = mlx90632_write_raw, +}; + +static int mlx90632_sleep(struct mlx90632_data *data) +{ + regcache_mark_dirty(data->regmap); + + dev_dbg(&data->client->dev, "Requesting sleep"); + return mlx90632_pwr_set_sleep_step(data->regmap); +} + +static int mlx90632_wakeup(struct mlx90632_data *data) +{ + int ret; + + ret = regcache_sync(data->regmap); + if (ret < 0) { + dev_err(&data->client->dev, + "Failed to sync regmap registers: %d\n", ret); + return ret; + } + + dev_dbg(&data->client->dev, "Requesting wake-up\n"); + return mlx90632_pwr_continuous(data->regmap); +} + +static int mlx90632_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct mlx90632_data *mlx90632; + struct regmap *regmap; + int ret; + unsigned int read; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90632)); + if (!indio_dev) { + dev_err(&client->dev, "Failed to allocate device\n"); + return -ENOMEM; + } + + regmap = devm_regmap_init_i2c(client, &mlx90632_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret); + return ret; + } + + mlx90632 = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + mlx90632->client = client; + mlx90632->regmap = regmap; + + mutex_init(&mlx90632->lock); + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mlx90632_info; + indio_dev->channels = mlx90632_channels; + indio_dev->num_channels = ARRAY_SIZE(mlx90632_channels); + + ret = mlx90632_wakeup(mlx90632); + if (ret < 0) { + dev_err(&client->dev, "Wakeup failed: %d\n", ret); + return ret; + } + + ret = regmap_read(mlx90632->regmap, MLX90632_EE_VERSION, &read); + if (ret < 0) { + dev_err(&client->dev, "read of version failed: %d\n", ret); + return ret; + } + if (read == MLX90632_ID_MEDICAL) { + dev_dbg(&client->dev, + "Detected Medical EEPROM calibration %x\n", read); + } else if (read == MLX90632_ID_CONSUMER) { + dev_dbg(&client->dev, + "Detected Consumer EEPROM calibration %x\n", read); + } else { + dev_err(&client->dev, + "EEPROM version mismatch %x (expected %x or %x)\n", + read, MLX90632_ID_CONSUMER, MLX90632_ID_MEDICAL); + return -EPROTONOSUPPORT; + } + + mlx90632->emissivity = 1000; + + pm_runtime_disable(&client->dev); + ret = pm_runtime_set_active(&client->dev); + if (ret < 0) { + mlx90632_sleep(mlx90632); + return ret; + } + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, MLX90632_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + return iio_device_register(indio_dev); +} + +static int mlx90632_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mlx90632_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + mlx90632_sleep(data); + + return 0; +} + +static const struct i2c_device_id mlx90632_id[] = { + { "mlx90632", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mlx90632_id); + +static const struct of_device_id mlx90632_of_match[] = { + { .compatible = "melexis,mlx90632" }, + { } +}; +MODULE_DEVICE_TABLE(of, mlx90632_of_match); + +static int __maybe_unused mlx90632_pm_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct mlx90632_data *data = iio_priv(indio_dev); + + return mlx90632_sleep(data); +} + +static int __maybe_unused mlx90632_pm_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct mlx90632_data *data = iio_priv(indio_dev); + + return mlx90632_wakeup(data); +} + +static UNIVERSAL_DEV_PM_OPS(mlx90632_pm_ops, mlx90632_pm_suspend, + mlx90632_pm_resume, NULL); + +static struct i2c_driver mlx90632_driver = { + .driver = { + .name = "mlx90632", + .of_match_table = mlx90632_of_match, + .pm = &mlx90632_pm_ops, + }, + .probe = mlx90632_probe, + .remove = mlx90632_remove, + .id_table = mlx90632_id, +}; +module_i2c_driver(mlx90632_driver); + +MODULE_AUTHOR("Crt Mori <cmo@melexis.com>"); +MODULE_DESCRIPTION("Melexis MLX90632 contactless Infra Red temperature sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 60d5982d8234..e9233db16e03 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -51,6 +51,12 @@ config ARM_GIC_V3_ITS_PCI depends on PCI_MSI default ARM_GIC_V3_ITS +config ARM_GIC_V3_ITS_FSL_MC + bool + depends on ARM_GIC_V3_ITS + depends on FSL_MC_BUS + default ARM_GIC_V3_ITS + config ARM_NVIC bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 280884068959..5ed465ab1c76 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-platform-msi.o irq-gic-v4.o obj-$(CONFIG_ARM_GIC_V3_ITS_PCI) += irq-gic-v3-its-pci-msi.o +obj-$(CONFIG_ARM_GIC_V3_ITS_FSL_MC) += irq-gic-v3-its-fsl-mc-msi.o obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o obj-$(CONFIG_ARM_NVIC) += irq-nvic.o diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c index fc2013aade51..4eca5c763766 100644 --- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c @@ -13,7 +13,7 @@ #include <linux/msi.h> #include <linux/of.h> #include <linux/of_irq.h> -#include "../include/mc.h" +#include <linux/fsl/mc.h> static struct irq_chip its_msi_irq_chip = { .name = "ITS-fMSI", @@ -43,9 +43,7 @@ static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain, * NOTE: This device id corresponds to the IOMMU stream ID * associated with the DPRC object (ICID). */ -#ifdef GENERIC_MSI_DOMAIN_OPS info->scratchpad[0].ul = mc_bus_dev->icid; -#endif msi_info = msi_get_domain_info(msi_domain->parent); return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); } diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index e95ab683331e..d5926f0d3f6c 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -24,8 +24,6 @@ menuconfig STAGING if STAGING -source "drivers/staging/irda/net/Kconfig" - source "drivers/staging/ipx/Kconfig" source "drivers/staging/ncpfs/Kconfig" @@ -114,12 +112,24 @@ source "drivers/staging/greybus/Kconfig" source "drivers/staging/vc04_services/Kconfig" -source "drivers/staging/ccree/Kconfig" - source "drivers/staging/typec/Kconfig" source "drivers/staging/vboxvideo/Kconfig" source "drivers/staging/pi433/Kconfig" +source "drivers/staging/mt7621-pinctrl/Kconfig" + +source "drivers/staging/mt7621-gpio/Kconfig" + +source "drivers/staging/mt7621-spi/Kconfig" + +source "drivers/staging/mt7621-dma/Kconfig" + +source "drivers/staging/mt7621-mmc/Kconfig" + +source "drivers/staging/mt7621-eth/Kconfig" + +source "drivers/staging/mt7621-dts/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index af8cd6a3a1f6..919753c3d3f6 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -5,8 +5,6 @@ obj-y += media/ obj-y += typec/ obj-$(CONFIG_IPX) += ipx/ obj-$(CONFIG_NCP_FS) += ncpfs/ -obj-$(CONFIG_IRDA) += irda/net/ -obj-$(CONFIG_IRDA) += irda/drivers/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ @@ -49,6 +47,13 @@ obj-$(CONFIG_MOST) += most/ obj-$(CONFIG_KS7010) += ks7010/ obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ -obj-$(CONFIG_CRYPTO_DEV_CCREE) += ccree/ obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/ obj-$(CONFIG_PI433) += pi433/ +obj-$(CONFIG_SOC_MT7621) += mt7621-pci/ +obj-$(CONFIG_SOC_MT7621) += mt7621-pinctrl/ +obj-$(CONFIG_SOC_MT7621) += mt7621-gpio/ +obj-$(CONFIG_SOC_MT7621) += mt7621-spi/ +obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ +obj-$(CONFIG_SOC_MT7621) += mt7621-mmc/ +obj-$(CONFIG_SOC_MT7621) += mt7621-eth/ +obj-$(CONFIG_SOC_MT7621) += mt7621-dts/ diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 86580b6df33d..a1a0025b59e0 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -321,7 +321,7 @@ out_unlock: static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin) { struct ashmem_area *asma = file->private_data; - int ret; + loff_t ret; mutex_lock(&ashmem_mutex); diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index 8f6494158d3d..898e9a834ccc 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -4,7 +4,7 @@ menuconfig ION select GENERIC_ALLOCATOR select DMA_SHARED_BUFFER ---help--- - Chose this option to enable the ION Memory Manager, + Choose this option to enable the ION Memory Manager, used by Android to efficiently allocate buffers from userspace that can be shared between drivers. If you're not using Android its probably safe to diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 57e0d8035b2e..e74db7902549 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -33,11 +33,6 @@ static struct ion_device *internal_dev; static int heap_id; -bool ion_buffer_cached(struct ion_buffer *buffer) -{ - return !!(buffer->flags & ION_FLAG_CACHED); -} - /* this function should only be called while dev->lock is held */ static void ion_buffer_add(struct ion_device *dev, struct ion_buffer *buffer) @@ -187,7 +182,7 @@ static struct sg_table *dup_sg_table(struct sg_table *table) new_sg = new_table->sgl; for_each_sg(table->sgl, sg, table->nents, i) { memcpy(new_sg, sg, sizeof(*sg)); - sg->dma_address = 0; + new_sg->dma_address = 0; new_sg = sg_next(new_sg); } @@ -527,7 +522,6 @@ DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get, void ion_device_add_heap(struct ion_heap *heap) { - struct dentry *debug_file; struct ion_device *dev = internal_dev; int ret; @@ -561,16 +555,8 @@ void ion_device_add_heap(struct ion_heap *heap) char debug_name[64]; snprintf(debug_name, 64, "%s_shrink", heap->name); - debug_file = debugfs_create_file(debug_name, - 0644, dev->debug_root, heap, - &debug_shrink_fops); - if (!debug_file) { - char buf[256], *path; - - path = dentry_path(dev->debug_root, buf, 256); - pr_err("Failed to create heap shrinker debugfs at %s/%s\n", - path, debug_name); - } + debugfs_create_file(debug_name, 0644, dev->debug_root, + heap, &debug_shrink_fops); } dev->heap_cnt++; @@ -599,12 +585,6 @@ static int ion_device_create(void) } idev->debug_root = debugfs_create_dir("ion", NULL); - if (!idev->debug_root) { - pr_err("ion: failed to create debugfs root directory.\n"); - goto debugfs_done; - } - -debugfs_done: idev->buffers = RB_ROOT; mutex_init(&idev->buffer_lock); init_rwsem(&idev->lock); diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index a238f23c9116..ea0897812780 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -185,23 +185,6 @@ struct ion_heap { }; /** - * ion_buffer_cached - this ion buffer is cached - * @buffer: buffer - * - * indicates whether this ion buffer is cached - */ -bool ion_buffer_cached(struct ion_buffer *buffer); - -/** - * ion_buffer_fault_user_mappings - fault in user mappings of this buffer - * @buffer: buffer - * - * indicates whether userspace mappings of this buffer will be faulted - * in, this can affect how buffers are allocated from the heap. - */ -bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer); - -/** * ion_device_add_heap - adds a heap to the ion device * @heap: the heap to add */ @@ -311,7 +294,6 @@ size_t ion_heap_freelist_size(struct ion_heap *heap); * @gfp_mask: gfp_mask to use from alloc * @order: order of pages in the pool * @list: plist node for list of pools - * @cached: it's cached pool or not * * Allows you to keep a pool of pre allocated pages to use from your heap. * Keeping a pool of pages that is ready for dma, ie any cached mapping have @@ -321,7 +303,6 @@ size_t ion_heap_freelist_size(struct ion_heap *heap); struct ion_page_pool { int high_count; int low_count; - bool cached; struct list_head high_items; struct list_head low_items; struct mutex mutex; @@ -330,8 +311,7 @@ struct ion_page_pool { struct plist_node list; }; -struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order, - bool cached); +struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order); void ion_page_pool_destroy(struct ion_page_pool *pool); struct page *ion_page_pool_alloc(struct ion_page_pool *pool); void ion_page_pool_free(struct ion_page_pool *pool, struct page *page); diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index b3017f12835f..db8f61446917 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -5,24 +5,15 @@ * Copyright (C) 2011 Google, Inc. */ -#include <linux/debugfs.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/fs.h> #include <linux/list.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/swap.h> #include "ion.h" -static void *ion_page_pool_alloc_pages(struct ion_page_pool *pool) +static inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool) { - struct page *page = alloc_pages(pool->gfp_mask, pool->order); - - if (!page) - return NULL; - return page; + return alloc_pages(pool->gfp_mask, pool->order); } static void ion_page_pool_free_pages(struct ion_page_pool *pool, @@ -31,7 +22,7 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, __free_pages(page, pool->order); } -static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) +static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { mutex_lock(&pool->mutex); if (PageHighMem(page)) { @@ -42,7 +33,6 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) pool->low_count++; } mutex_unlock(&pool->mutex); - return 0; } static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) @@ -84,13 +74,9 @@ struct page *ion_page_pool_alloc(struct ion_page_pool *pool) void ion_page_pool_free(struct ion_page_pool *pool, struct page *page) { - int ret; - BUG_ON(pool->order != compound_order(page)); - ret = ion_page_pool_add(pool, page); - if (ret) - ion_page_pool_free_pages(pool, page); + ion_page_pool_add(pool, page); } static int ion_page_pool_total(struct ion_page_pool *pool, bool high) @@ -137,8 +123,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, return freed; } -struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order, - bool cached) +struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order) { struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL); @@ -152,8 +137,6 @@ struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order, pool->order = order; mutex_init(&pool->mutex); plist_node_init(&pool->list, order); - if (cached) - pool->cached = true; return pool; } @@ -162,9 +145,3 @@ void ion_page_pool_destroy(struct ion_page_pool *pool) { kfree(pool); } - -static int __init ion_page_pool_init(void) -{ - return 0; -} -device_initcall(ion_page_pool_init); diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index bc19cdd30637..701eb9f3b0f1 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -41,31 +41,16 @@ static inline unsigned int order_to_size(int order) struct ion_system_heap { struct ion_heap heap; - struct ion_page_pool *uncached_pools[NUM_ORDERS]; - struct ion_page_pool *cached_pools[NUM_ORDERS]; + struct ion_page_pool *pools[NUM_ORDERS]; }; -/** - * The page from page-pool are all zeroed before. We need do cache - * clean for cached buffer. The uncached buffer are always non-cached - * since it's allocated. So no need for non-cached pages. - */ static struct page *alloc_buffer_page(struct ion_system_heap *heap, struct ion_buffer *buffer, unsigned long order) { - bool cached = ion_buffer_cached(buffer); - struct ion_page_pool *pool; - struct page *page; + struct ion_page_pool *pool = heap->pools[order_to_index(order)]; - if (!cached) - pool = heap->uncached_pools[order_to_index(order)]; - else - pool = heap->cached_pools[order_to_index(order)]; - - page = ion_page_pool_alloc(pool); - - return page; + return ion_page_pool_alloc(pool); } static void free_buffer_page(struct ion_system_heap *heap, @@ -73,7 +58,6 @@ static void free_buffer_page(struct ion_system_heap *heap, { struct ion_page_pool *pool; unsigned int order = compound_order(page); - bool cached = ion_buffer_cached(buffer); /* go to system */ if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) { @@ -81,10 +65,7 @@ static void free_buffer_page(struct ion_system_heap *heap, return; } - if (!cached) - pool = heap->uncached_pools[order_to_index(order)]; - else - pool = heap->cached_pools[order_to_index(order)]; + pool = heap->pools[order_to_index(order)]; ion_page_pool_free(pool, page); } @@ -190,8 +171,7 @@ static void ion_system_heap_free(struct ion_buffer *buffer) static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, int nr_to_scan) { - struct ion_page_pool *uncached_pool; - struct ion_page_pool *cached_pool; + struct ion_page_pool *pool; struct ion_system_heap *sys_heap; int nr_total = 0; int i, nr_freed; @@ -203,26 +183,15 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, only_scan = 1; for (i = 0; i < NUM_ORDERS; i++) { - uncached_pool = sys_heap->uncached_pools[i]; - cached_pool = sys_heap->cached_pools[i]; + pool = sys_heap->pools[i]; if (only_scan) { - nr_total += ion_page_pool_shrink(uncached_pool, + nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); - nr_total += ion_page_pool_shrink(cached_pool, - gfp_mask, - nr_to_scan); } else { - nr_freed = ion_page_pool_shrink(uncached_pool, - gfp_mask, - nr_to_scan); - nr_to_scan -= nr_freed; - nr_total += nr_freed; - if (nr_to_scan <= 0) - break; - nr_freed = ion_page_pool_shrink(cached_pool, + nr_freed = ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); nr_to_scan -= nr_freed; @@ -253,26 +222,16 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, struct ion_page_pool *pool; for (i = 0; i < NUM_ORDERS; i++) { - pool = sys_heap->uncached_pools[i]; + pool = sys_heap->pools[i]; - seq_printf(s, "%d order %u highmem pages uncached %lu total\n", + seq_printf(s, "%d order %u highmem pages %lu total\n", pool->high_count, pool->order, (PAGE_SIZE << pool->order) * pool->high_count); - seq_printf(s, "%d order %u lowmem pages uncached %lu total\n", + seq_printf(s, "%d order %u lowmem pages %lu total\n", pool->low_count, pool->order, (PAGE_SIZE << pool->order) * pool->low_count); } - for (i = 0; i < NUM_ORDERS; i++) { - pool = sys_heap->cached_pools[i]; - - seq_printf(s, "%d order %u highmem pages cached %lu total\n", - pool->high_count, pool->order, - (PAGE_SIZE << pool->order) * pool->high_count); - seq_printf(s, "%d order %u lowmem pages cached %lu total\n", - pool->low_count, pool->order, - (PAGE_SIZE << pool->order) * pool->low_count); - } return 0; } @@ -285,8 +244,7 @@ static void ion_system_heap_destroy_pools(struct ion_page_pool **pools) ion_page_pool_destroy(pools[i]); } -static int ion_system_heap_create_pools(struct ion_page_pool **pools, - bool cached) +static int ion_system_heap_create_pools(struct ion_page_pool **pools) { int i; gfp_t gfp_flags = low_order_gfp_flags; @@ -297,7 +255,7 @@ static int ion_system_heap_create_pools(struct ion_page_pool **pools, if (orders[i] > 4) gfp_flags = high_order_gfp_flags; - pool = ion_page_pool_create(gfp_flags, orders[i], cached); + pool = ion_page_pool_create(gfp_flags, orders[i]); if (!pool) goto err_create_pool; pools[i] = pool; @@ -320,18 +278,12 @@ static struct ion_heap *__ion_system_heap_create(void) heap->heap.type = ION_HEAP_TYPE_SYSTEM; heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; - if (ion_system_heap_create_pools(heap->uncached_pools, false)) + if (ion_system_heap_create_pools(heap->pools)) goto free_heap; - if (ion_system_heap_create_pools(heap->cached_pools, true)) - goto destroy_uncached_pools; - heap->heap.debug_show = ion_system_heap_debug_show; return &heap->heap; -destroy_uncached_pools: - ion_system_heap_destroy_pools(heap->uncached_pools); - free_heap: kfree(heap); return ERR_PTR(-ENOMEM); diff --git a/drivers/staging/ccree/Kconfig b/drivers/staging/ccree/Kconfig deleted file mode 100644 index 168191fa0357..000000000000 --- a/drivers/staging/ccree/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -config CRYPTO_DEV_CCREE_OLD - tristate "Support for ARM TrustZone CryptoCell C7XX family of Crypto accelerators" - depends on CRYPTO && CRYPTO_HW && OF && HAS_DMA && BROKEN - default n - select CRYPTO_HASH - select CRYPTO_BLKCIPHER - select CRYPTO_DES - select CRYPTO_AEAD - select CRYPTO_AUTHENC - select CRYPTO_SHA1 - select CRYPTO_MD5 - select CRYPTO_SHA256 - select CRYPTO_SHA512 - select CRYPTO_HMAC - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_CTR - select CRYPTO_XTS - help - Say 'Y' to enable a driver for the Arm TrustZone CryptoCell - C7xx. Currently only the CryptoCell 712 REE is supported. - Choose this if you wish to use hardware acceleration of - cryptographic operations on the system REE. - If unsure say Y. diff --git a/drivers/staging/ccree/Makefile b/drivers/staging/ccree/Makefile deleted file mode 100644 index 553db5c45354..000000000000 --- a/drivers/staging/ccree/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_CRYPTO_DEV_CCREE_OLD) := ccree.o -ccree-y := cc_driver.o cc_buffer_mgr.o cc_request_mgr.o cc_cipher.o cc_hash.o cc_aead.o cc_ivgen.o cc_sram_mgr.o -ccree-$(CONFIG_CRYPTO_FIPS) += cc_fips.o -ccree-$(CONFIG_DEBUG_FS) += cc_debugfs.o -ccree-$(CONFIG_PM) += cc_pm.o diff --git a/drivers/staging/ccree/TODO b/drivers/staging/ccree/TODO deleted file mode 100644 index b8e163d98f91..000000000000 --- a/drivers/staging/ccree/TODO +++ /dev/null @@ -1,10 +0,0 @@ - - -************************************************************************* -* * -* Arm Trust Zone CryptoCell REE Linux driver upstreaming TODO items * -* * -************************************************************************* - -1. ??? - diff --git a/drivers/staging/ccree/cc_aead.c b/drivers/staging/ccree/cc_aead.c deleted file mode 100644 index b58413172231..000000000000 --- a/drivers/staging/ccree/cc_aead.c +++ /dev/null @@ -1,2701 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <crypto/algapi.h> -#include <crypto/internal/aead.h> -#include <crypto/authenc.h> -#include <crypto/des.h> -#include <linux/rtnetlink.h> -#include "cc_driver.h" -#include "cc_buffer_mgr.h" -#include "cc_aead.h" -#include "cc_request_mgr.h" -#include "cc_hash.h" -#include "cc_sram_mgr.h" - -#define template_aead template_u.aead - -#define MAX_AEAD_SETKEY_SEQ 12 -#define MAX_AEAD_PROCESS_SEQ 23 - -#define MAX_HMAC_DIGEST_SIZE (SHA256_DIGEST_SIZE) -#define MAX_HMAC_BLOCK_SIZE (SHA256_BLOCK_SIZE) - -#define AES_CCM_RFC4309_NONCE_SIZE 3 -#define MAX_NONCE_SIZE CTR_RFC3686_NONCE_SIZE - -/* Value of each ICV_CMP byte (of 8) in case of success */ -#define ICV_VERIF_OK 0x01 - -struct cc_aead_handle { - cc_sram_addr_t sram_workspace_addr; - struct list_head aead_list; -}; - -struct cc_hmac_s { - u8 *padded_authkey; - u8 *ipad_opad; /* IPAD, OPAD*/ - dma_addr_t padded_authkey_dma_addr; - dma_addr_t ipad_opad_dma_addr; -}; - -struct cc_xcbc_s { - u8 *xcbc_keys; /* K1,K2,K3 */ - dma_addr_t xcbc_keys_dma_addr; -}; - -struct cc_aead_ctx { - struct cc_drvdata *drvdata; - u8 ctr_nonce[MAX_NONCE_SIZE]; /* used for ctr3686 iv and aes ccm */ - u8 *enckey; - dma_addr_t enckey_dma_addr; - union { - struct cc_hmac_s hmac; - struct cc_xcbc_s xcbc; - } auth_state; - unsigned int enc_keylen; - unsigned int auth_keylen; - unsigned int authsize; /* Actual (reduced?) size of the MAC/ICv */ - enum drv_cipher_mode cipher_mode; - enum cc_flow_mode flow_mode; - enum drv_hash_mode auth_mode; -}; - -static inline bool valid_assoclen(struct aead_request *req) -{ - return ((req->assoclen == 16) || (req->assoclen == 20)); -} - -static void cc_aead_exit(struct crypto_aead *tfm) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "Clearing context @%p for %s\n", crypto_aead_ctx(tfm), - crypto_tfm_alg_name(&tfm->base)); - - /* Unmap enckey buffer */ - if (ctx->enckey) { - dma_free_coherent(dev, AES_MAX_KEY_SIZE, ctx->enckey, - ctx->enckey_dma_addr); - dev_dbg(dev, "Freed enckey DMA buffer enckey_dma_addr=%pad\n", - &ctx->enckey_dma_addr); - ctx->enckey_dma_addr = 0; - ctx->enckey = NULL; - } - - if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */ - struct cc_xcbc_s *xcbc = &ctx->auth_state.xcbc; - - if (xcbc->xcbc_keys) { - dma_free_coherent(dev, CC_AES_128_BIT_KEY_SIZE * 3, - xcbc->xcbc_keys, - xcbc->xcbc_keys_dma_addr); - } - dev_dbg(dev, "Freed xcbc_keys DMA buffer xcbc_keys_dma_addr=%pad\n", - &xcbc->xcbc_keys_dma_addr); - xcbc->xcbc_keys_dma_addr = 0; - xcbc->xcbc_keys = NULL; - } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC auth. */ - struct cc_hmac_s *hmac = &ctx->auth_state.hmac; - - if (hmac->ipad_opad) { - dma_free_coherent(dev, 2 * MAX_HMAC_DIGEST_SIZE, - hmac->ipad_opad, - hmac->ipad_opad_dma_addr); - dev_dbg(dev, "Freed ipad_opad DMA buffer ipad_opad_dma_addr=%pad\n", - &hmac->ipad_opad_dma_addr); - hmac->ipad_opad_dma_addr = 0; - hmac->ipad_opad = NULL; - } - if (hmac->padded_authkey) { - dma_free_coherent(dev, MAX_HMAC_BLOCK_SIZE, - hmac->padded_authkey, - hmac->padded_authkey_dma_addr); - dev_dbg(dev, "Freed padded_authkey DMA buffer padded_authkey_dma_addr=%pad\n", - &hmac->padded_authkey_dma_addr); - hmac->padded_authkey_dma_addr = 0; - hmac->padded_authkey = NULL; - } - } -} - -static int cc_aead_init(struct crypto_aead *tfm) -{ - struct aead_alg *alg = crypto_aead_alg(tfm); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct cc_crypto_alg *cc_alg = - container_of(alg, struct cc_crypto_alg, aead_alg); - struct device *dev = drvdata_to_dev(cc_alg->drvdata); - - dev_dbg(dev, "Initializing context @%p for %s\n", ctx, - crypto_tfm_alg_name(&tfm->base)); - - /* Initialize modes in instance */ - ctx->cipher_mode = cc_alg->cipher_mode; - ctx->flow_mode = cc_alg->flow_mode; - ctx->auth_mode = cc_alg->auth_mode; - ctx->drvdata = cc_alg->drvdata; - crypto_aead_set_reqsize(tfm, sizeof(struct aead_req_ctx)); - - /* Allocate key buffer, cache line aligned */ - ctx->enckey = dma_alloc_coherent(dev, AES_MAX_KEY_SIZE, - &ctx->enckey_dma_addr, GFP_KERNEL); - if (!ctx->enckey) { - dev_err(dev, "Failed allocating key buffer\n"); - goto init_failed; - } - dev_dbg(dev, "Allocated enckey buffer in context ctx->enckey=@%p\n", - ctx->enckey); - - /* Set default authlen value */ - - if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */ - struct cc_xcbc_s *xcbc = &ctx->auth_state.xcbc; - const unsigned int key_size = CC_AES_128_BIT_KEY_SIZE * 3; - - /* Allocate dma-coherent buffer for XCBC's K1+K2+K3 */ - /* (and temporary for user key - up to 256b) */ - xcbc->xcbc_keys = dma_alloc_coherent(dev, key_size, - &xcbc->xcbc_keys_dma_addr, - GFP_KERNEL); - if (!xcbc->xcbc_keys) { - dev_err(dev, "Failed allocating buffer for XCBC keys\n"); - goto init_failed; - } - } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC authentication */ - struct cc_hmac_s *hmac = &ctx->auth_state.hmac; - const unsigned int digest_size = 2 * MAX_HMAC_DIGEST_SIZE; - dma_addr_t *pkey_dma = &hmac->padded_authkey_dma_addr; - - /* Allocate dma-coherent buffer for IPAD + OPAD */ - hmac->ipad_opad = dma_alloc_coherent(dev, digest_size, - &hmac->ipad_opad_dma_addr, - GFP_KERNEL); - - if (!hmac->ipad_opad) { - dev_err(dev, "Failed allocating IPAD/OPAD buffer\n"); - goto init_failed; - } - - dev_dbg(dev, "Allocated authkey buffer in context ctx->authkey=@%p\n", - hmac->ipad_opad); - - hmac->padded_authkey = dma_alloc_coherent(dev, - MAX_HMAC_BLOCK_SIZE, - pkey_dma, - GFP_KERNEL); - - if (!hmac->padded_authkey) { - dev_err(dev, "failed to allocate padded_authkey\n"); - goto init_failed; - } - } else { - ctx->auth_state.hmac.ipad_opad = NULL; - ctx->auth_state.hmac.padded_authkey = NULL; - } - - return 0; - -init_failed: - cc_aead_exit(tfm); - return -ENOMEM; -} - -static void cc_aead_complete(struct device *dev, void *cc_req, int err) -{ - struct aead_request *areq = (struct aead_request *)cc_req; - struct aead_req_ctx *areq_ctx = aead_request_ctx(areq); - struct crypto_aead *tfm = crypto_aead_reqtfm(cc_req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - - cc_unmap_aead_request(dev, areq); - - /* Restore ordinary iv pointer */ - areq->iv = areq_ctx->backup_iv; - - if (err) - goto done; - - if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) { - if (memcmp(areq_ctx->mac_buf, areq_ctx->icv_virt_addr, - ctx->authsize) != 0) { - dev_dbg(dev, "Payload authentication failure, (auth-size=%d, cipher=%d)\n", - ctx->authsize, ctx->cipher_mode); - /* In case of payload authentication failure, MUST NOT - * revealed the decrypted message --> zero its memory. - */ - cc_zero_sgl(areq->dst, areq_ctx->cryptlen); - err = -EBADMSG; - } - } else { /*ENCRYPT*/ - if (areq_ctx->is_icv_fragmented) { - u32 skip = areq->cryptlen + areq_ctx->dst_offset; - - cc_copy_sg_portion(dev, areq_ctx->mac_buf, - areq_ctx->dst_sgl, skip, - (skip + ctx->authsize), - CC_SG_FROM_BUF); - } - - /* If an IV was generated, copy it back to the user provided - * buffer. - */ - if (areq_ctx->backup_giv) { - if (ctx->cipher_mode == DRV_CIPHER_CTR) - memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv + - CTR_RFC3686_NONCE_SIZE, - CTR_RFC3686_IV_SIZE); - else if (ctx->cipher_mode == DRV_CIPHER_CCM) - memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv + - CCM_BLOCK_IV_OFFSET, CCM_BLOCK_IV_SIZE); - } - } -done: - aead_request_complete(areq, err); -} - -static int xcbc_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx) -{ - /* Load the AES key */ - hw_desc_init(&desc[0]); - /* We are using for the source/user key the same buffer - * as for the output keys, * because after this key loading it - * is not needed anymore - */ - set_din_type(&desc[0], DMA_DLLI, - ctx->auth_state.xcbc.xcbc_keys_dma_addr, ctx->auth_keylen, - NS_BIT); - set_cipher_mode(&desc[0], DRV_CIPHER_ECB); - set_cipher_config0(&desc[0], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_key_size_aes(&desc[0], ctx->auth_keylen); - set_flow_mode(&desc[0], S_DIN_to_AES); - set_setup_mode(&desc[0], SETUP_LOAD_KEY0); - - hw_desc_init(&desc[1]); - set_din_const(&desc[1], 0x01010101, CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[1], DIN_AES_DOUT); - set_dout_dlli(&desc[1], ctx->auth_state.xcbc.xcbc_keys_dma_addr, - AES_KEYSIZE_128, NS_BIT, 0); - - hw_desc_init(&desc[2]); - set_din_const(&desc[2], 0x02020202, CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[2], DIN_AES_DOUT); - set_dout_dlli(&desc[2], (ctx->auth_state.xcbc.xcbc_keys_dma_addr - + AES_KEYSIZE_128), - AES_KEYSIZE_128, NS_BIT, 0); - - hw_desc_init(&desc[3]); - set_din_const(&desc[3], 0x03030303, CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[3], DIN_AES_DOUT); - set_dout_dlli(&desc[3], (ctx->auth_state.xcbc.xcbc_keys_dma_addr - + 2 * AES_KEYSIZE_128), - AES_KEYSIZE_128, NS_BIT, 0); - - return 4; -} - -static int hmac_setkey(struct cc_hw_desc *desc, struct cc_aead_ctx *ctx) -{ - unsigned int hmac_pad_const[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST }; - unsigned int digest_ofs = 0; - unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ? - DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256; - unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ? - CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE; - struct cc_hmac_s *hmac = &ctx->auth_state.hmac; - - int idx = 0; - int i; - - /* calc derived HMAC key */ - for (i = 0; i < 2; i++) { - /* Load hash initial state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_din_sram(&desc[idx], - cc_larval_digest_addr(ctx->drvdata, - ctx->auth_mode), - digest_size); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_din_const(&desc[idx], 0, HASH_LEN_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Prepare ipad key */ - hw_desc_init(&desc[idx]); - set_xor_val(&desc[idx], hmac_pad_const[i]); - set_cipher_mode(&desc[idx], hash_mode); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - idx++; - - /* Perform HASH update */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - hmac->padded_authkey_dma_addr, - SHA256_BLOCK_SIZE, NS_BIT); - set_cipher_mode(&desc[idx], hash_mode); - set_xor_active(&desc[idx]); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Get the digset */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_dout_dlli(&desc[idx], - (hmac->ipad_opad_dma_addr + digest_ofs), - digest_size, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - idx++; - - digest_ofs += digest_size; - } - - return idx; -} - -static int validate_keys_sizes(struct cc_aead_ctx *ctx) -{ - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "enc_keylen=%u authkeylen=%u\n", - ctx->enc_keylen, ctx->auth_keylen); - - switch (ctx->auth_mode) { - case DRV_HASH_SHA1: - case DRV_HASH_SHA256: - break; - case DRV_HASH_XCBC_MAC: - if (ctx->auth_keylen != AES_KEYSIZE_128 && - ctx->auth_keylen != AES_KEYSIZE_192 && - ctx->auth_keylen != AES_KEYSIZE_256) - return -ENOTSUPP; - break; - case DRV_HASH_NULL: /* Not authenc (e.g., CCM) - no auth_key) */ - if (ctx->auth_keylen > 0) - return -EINVAL; - break; - default: - dev_err(dev, "Invalid auth_mode=%d\n", ctx->auth_mode); - return -EINVAL; - } - /* Check cipher key size */ - if (ctx->flow_mode == S_DIN_to_DES) { - if (ctx->enc_keylen != DES3_EDE_KEY_SIZE) { - dev_err(dev, "Invalid cipher(3DES) key size: %u\n", - ctx->enc_keylen); - return -EINVAL; - } - } else { /* Default assumed to be AES ciphers */ - if (ctx->enc_keylen != AES_KEYSIZE_128 && - ctx->enc_keylen != AES_KEYSIZE_192 && - ctx->enc_keylen != AES_KEYSIZE_256) { - dev_err(dev, "Invalid cipher(AES) key size: %u\n", - ctx->enc_keylen); - return -EINVAL; - } - } - - return 0; /* All tests of keys sizes passed */ -} - -/* This function prepers the user key so it can pass to the hmac processing - * (copy to intenral buffer or hash in case of key longer than block - */ -static int -cc_get_plain_hmac_key(struct crypto_aead *tfm, const u8 *key, - unsigned int keylen) -{ - dma_addr_t key_dma_addr = 0; - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - u32 larval_addr = cc_larval_digest_addr(ctx->drvdata, ctx->auth_mode); - struct cc_crypto_req cc_req = {}; - unsigned int blocksize; - unsigned int digestsize; - unsigned int hashmode; - unsigned int idx = 0; - int rc = 0; - struct cc_hw_desc desc[MAX_AEAD_SETKEY_SEQ]; - dma_addr_t padded_authkey_dma_addr = - ctx->auth_state.hmac.padded_authkey_dma_addr; - - switch (ctx->auth_mode) { /* auth_key required and >0 */ - case DRV_HASH_SHA1: - blocksize = SHA1_BLOCK_SIZE; - digestsize = SHA1_DIGEST_SIZE; - hashmode = DRV_HASH_HW_SHA1; - break; - case DRV_HASH_SHA256: - default: - blocksize = SHA256_BLOCK_SIZE; - digestsize = SHA256_DIGEST_SIZE; - hashmode = DRV_HASH_HW_SHA256; - } - - if (keylen != 0) { - key_dma_addr = dma_map_single(dev, (void *)key, keylen, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, key_dma_addr)) { - dev_err(dev, "Mapping key va=0x%p len=%u for DMA failed\n", - key, keylen); - return -ENOMEM; - } - if (keylen > blocksize) { - /* Load hash initial state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hashmode); - set_din_sram(&desc[idx], larval_addr, digestsize); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hashmode); - set_din_const(&desc[idx], 0, HASH_LEN_SIZE); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - key_dma_addr, keylen, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Get hashed key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hashmode); - set_dout_dlli(&desc[idx], padded_authkey_dma_addr, - digestsize, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - set_cipher_config0(&desc[idx], - HASH_DIGEST_RESULT_LITTLE_ENDIAN); - idx++; - - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, (blocksize - digestsize)); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], (padded_authkey_dma_addr + - digestsize), (blocksize - digestsize), - NS_BIT, 0); - idx++; - } else { - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, key_dma_addr, - keylen, NS_BIT); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], padded_authkey_dma_addr, - keylen, NS_BIT, 0); - idx++; - - if ((blocksize - keylen) != 0) { - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, - (blocksize - keylen)); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], - (padded_authkey_dma_addr + - keylen), - (blocksize - keylen), NS_BIT, 0); - idx++; - } - } - } else { - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, (blocksize - keylen)); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], padded_authkey_dma_addr, - blocksize, NS_BIT, 0); - idx++; - } - - rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx); - if (rc) - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - - if (key_dma_addr) - dma_unmap_single(dev, key_dma_addr, keylen, DMA_TO_DEVICE); - - return rc; -} - -static int -cc_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct rtattr *rta = (struct rtattr *)key; - struct cc_crypto_req cc_req = {}; - struct crypto_authenc_key_param *param; - struct cc_hw_desc desc[MAX_AEAD_SETKEY_SEQ]; - int seq_len = 0, rc = -EINVAL; - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "Setting key in context @%p for %s. key=%p keylen=%u\n", - ctx, crypto_tfm_alg_name(crypto_aead_tfm(tfm)), key, keylen); - - /* STAT_PHASE_0: Init and sanity checks */ - - if (ctx->auth_mode != DRV_HASH_NULL) { /* authenc() alg. */ - if (!RTA_OK(rta, keylen)) - goto badkey; - if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM) - goto badkey; - if (RTA_PAYLOAD(rta) < sizeof(*param)) - goto badkey; - param = RTA_DATA(rta); - ctx->enc_keylen = be32_to_cpu(param->enckeylen); - key += RTA_ALIGN(rta->rta_len); - keylen -= RTA_ALIGN(rta->rta_len); - if (keylen < ctx->enc_keylen) - goto badkey; - ctx->auth_keylen = keylen - ctx->enc_keylen; - - if (ctx->cipher_mode == DRV_CIPHER_CTR) { - /* the nonce is stored in bytes at end of key */ - if (ctx->enc_keylen < - (AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE)) - goto badkey; - /* Copy nonce from last 4 bytes in CTR key to - * first 4 bytes in CTR IV - */ - memcpy(ctx->ctr_nonce, key + ctx->auth_keylen + - ctx->enc_keylen - CTR_RFC3686_NONCE_SIZE, - CTR_RFC3686_NONCE_SIZE); - /* Set CTR key size */ - ctx->enc_keylen -= CTR_RFC3686_NONCE_SIZE; - } - } else { /* non-authenc - has just one key */ - ctx->enc_keylen = keylen; - ctx->auth_keylen = 0; - } - - rc = validate_keys_sizes(ctx); - if (rc) - goto badkey; - - /* STAT_PHASE_1: Copy key to ctx */ - - /* Get key material */ - memcpy(ctx->enckey, key + ctx->auth_keylen, ctx->enc_keylen); - if (ctx->enc_keylen == 24) - memset(ctx->enckey + 24, 0, CC_AES_KEY_SIZE_MAX - 24); - if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { - memcpy(ctx->auth_state.xcbc.xcbc_keys, key, ctx->auth_keylen); - } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC */ - rc = cc_get_plain_hmac_key(tfm, key, ctx->auth_keylen); - if (rc) - goto badkey; - } - - /* STAT_PHASE_2: Create sequence */ - - switch (ctx->auth_mode) { - case DRV_HASH_SHA1: - case DRV_HASH_SHA256: - seq_len = hmac_setkey(desc, ctx); - break; - case DRV_HASH_XCBC_MAC: - seq_len = xcbc_setkey(desc, ctx); - break; - case DRV_HASH_NULL: /* non-authenc modes, e.g., CCM */ - break; /* No auth. key setup */ - default: - dev_err(dev, "Unsupported authenc (%d)\n", ctx->auth_mode); - rc = -ENOTSUPP; - goto badkey; - } - - /* STAT_PHASE_3: Submit sequence to HW */ - - if (seq_len > 0) { /* For CCM there is no sequence to setup the key */ - rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, seq_len); - if (rc) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - goto setkey_error; - } - } - - /* Update STAT_PHASE_3 */ - return rc; - -badkey: - crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - -setkey_error: - return rc; -} - -static int cc_rfc4309_ccm_setkey(struct crypto_aead *tfm, const u8 *key, - unsigned int keylen) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - - if (keylen < 3) - return -EINVAL; - - keylen -= 3; - memcpy(ctx->ctr_nonce, key + keylen, 3); - - return cc_aead_setkey(tfm, key, keylen); -} - -static int cc_aead_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(authenc); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - /* Unsupported auth. sizes */ - if (authsize == 0 || - authsize > crypto_aead_maxauthsize(authenc)) { - return -ENOTSUPP; - } - - ctx->authsize = authsize; - dev_dbg(dev, "authlen=%d\n", ctx->authsize); - - return 0; -} - -static int cc_rfc4309_ccm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - switch (authsize) { - case 8: - case 12: - case 16: - break; - default: - return -EINVAL; - } - - return cc_aead_setauthsize(authenc, authsize); -} - -static int cc_ccm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - switch (authsize) { - case 4: - case 6: - case 8: - case 10: - case 12: - case 14: - case 16: - break; - default: - return -EINVAL; - } - - return cc_aead_setauthsize(authenc, authsize); -} - -static void cc_set_assoc_desc(struct aead_request *areq, unsigned int flow_mode, - struct cc_hw_desc desc[], unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(areq); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *areq_ctx = aead_request_ctx(areq); - enum cc_req_dma_buf_type assoc_dma_type = areq_ctx->assoc_buff_type; - unsigned int idx = *seq_size; - struct device *dev = drvdata_to_dev(ctx->drvdata); - - switch (assoc_dma_type) { - case CC_DMA_BUF_DLLI: - dev_dbg(dev, "ASSOC buffer type DLLI\n"); - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, sg_dma_address(areq->src), - areq->assoclen, NS_BIT); - set_flow_mode(&desc[idx], flow_mode); - if (ctx->auth_mode == DRV_HASH_XCBC_MAC && - areq_ctx->cryptlen > 0) - set_din_not_last_indication(&desc[idx]); - break; - case CC_DMA_BUF_MLLI: - dev_dbg(dev, "ASSOC buffer type MLLI\n"); - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_MLLI, areq_ctx->assoc.sram_addr, - areq_ctx->assoc.mlli_nents, NS_BIT); - set_flow_mode(&desc[idx], flow_mode); - if (ctx->auth_mode == DRV_HASH_XCBC_MAC && - areq_ctx->cryptlen > 0) - set_din_not_last_indication(&desc[idx]); - break; - case CC_DMA_BUF_NULL: - default: - dev_err(dev, "Invalid ASSOC buffer type\n"); - } - - *seq_size = (++idx); -} - -static void cc_proc_authen_desc(struct aead_request *areq, - unsigned int flow_mode, - struct cc_hw_desc desc[], - unsigned int *seq_size, int direct) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(areq); - enum cc_req_dma_buf_type data_dma_type = areq_ctx->data_buff_type; - unsigned int idx = *seq_size; - struct crypto_aead *tfm = crypto_aead_reqtfm(areq); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - switch (data_dma_type) { - case CC_DMA_BUF_DLLI: - { - struct scatterlist *cipher = - (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? - areq_ctx->dst_sgl : areq_ctx->src_sgl; - - unsigned int offset = - (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? - areq_ctx->dst_offset : areq_ctx->src_offset; - dev_dbg(dev, "AUTHENC: SRC/DST buffer type DLLI\n"); - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - (sg_dma_address(cipher) + offset), - areq_ctx->cryptlen, NS_BIT); - set_flow_mode(&desc[idx], flow_mode); - break; - } - case CC_DMA_BUF_MLLI: - { - /* DOUBLE-PASS flow (as default) - * assoc. + iv + data -compact in one table - * if assoclen is ZERO only IV perform - */ - cc_sram_addr_t mlli_addr = areq_ctx->assoc.sram_addr; - u32 mlli_nents = areq_ctx->assoc.mlli_nents; - - if (areq_ctx->is_single_pass) { - if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) { - mlli_addr = areq_ctx->dst.sram_addr; - mlli_nents = areq_ctx->dst.mlli_nents; - } else { - mlli_addr = areq_ctx->src.sram_addr; - mlli_nents = areq_ctx->src.mlli_nents; - } - } - - dev_dbg(dev, "AUTHENC: SRC/DST buffer type MLLI\n"); - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_MLLI, mlli_addr, mlli_nents, - NS_BIT); - set_flow_mode(&desc[idx], flow_mode); - break; - } - case CC_DMA_BUF_NULL: - default: - dev_err(dev, "AUTHENC: Invalid SRC/DST buffer type\n"); - } - - *seq_size = (++idx); -} - -static void cc_proc_cipher_desc(struct aead_request *areq, - unsigned int flow_mode, - struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - unsigned int idx = *seq_size; - struct aead_req_ctx *areq_ctx = aead_request_ctx(areq); - enum cc_req_dma_buf_type data_dma_type = areq_ctx->data_buff_type; - struct crypto_aead *tfm = crypto_aead_reqtfm(areq); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - if (areq_ctx->cryptlen == 0) - return; /*null processing*/ - - switch (data_dma_type) { - case CC_DMA_BUF_DLLI: - dev_dbg(dev, "CIPHER: SRC/DST buffer type DLLI\n"); - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - (sg_dma_address(areq_ctx->src_sgl) + - areq_ctx->src_offset), areq_ctx->cryptlen, - NS_BIT); - set_dout_dlli(&desc[idx], - (sg_dma_address(areq_ctx->dst_sgl) + - areq_ctx->dst_offset), - areq_ctx->cryptlen, NS_BIT, 0); - set_flow_mode(&desc[idx], flow_mode); - break; - case CC_DMA_BUF_MLLI: - dev_dbg(dev, "CIPHER: SRC/DST buffer type MLLI\n"); - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_MLLI, areq_ctx->src.sram_addr, - areq_ctx->src.mlli_nents, NS_BIT); - set_dout_mlli(&desc[idx], areq_ctx->dst.sram_addr, - areq_ctx->dst.mlli_nents, NS_BIT, 0); - set_flow_mode(&desc[idx], flow_mode); - break; - case CC_DMA_BUF_NULL: - default: - dev_err(dev, "CIPHER: Invalid SRC/DST buffer type\n"); - } - - *seq_size = (++idx); -} - -static void cc_proc_digest_desc(struct aead_request *req, - struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - unsigned int idx = *seq_size; - unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ? - DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256; - int direct = req_ctx->gen_ctx.op_type; - - /* Get final ICV result */ - if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) { - hw_desc_init(&desc[idx]); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_dout_dlli(&desc[idx], req_ctx->icv_dma_addr, ctx->authsize, - NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { - set_aes_not_hash_mode(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - } else { - set_cipher_config0(&desc[idx], - HASH_DIGEST_RESULT_LITTLE_ENDIAN); - set_cipher_mode(&desc[idx], hash_mode); - } - } else { /*Decrypt*/ - /* Get ICV out from hardware */ - hw_desc_init(&desc[idx]); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_dout_dlli(&desc[idx], req_ctx->mac_buf_dma_addr, - ctx->authsize, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_cipher_config0(&desc[idx], - HASH_DIGEST_RESULT_LITTLE_ENDIAN); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_aes_not_hash_mode(&desc[idx]); - } else { - set_cipher_mode(&desc[idx], hash_mode); - } - } - - *seq_size = (++idx); -} - -static void cc_set_cipher_desc(struct aead_request *req, - struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - unsigned int hw_iv_size = req_ctx->hw_iv_size; - unsigned int idx = *seq_size; - int direct = req_ctx->gen_ctx.op_type; - - /* Setup cipher state */ - hw_desc_init(&desc[idx]); - set_cipher_config0(&desc[idx], direct); - set_flow_mode(&desc[idx], ctx->flow_mode); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->gen_ctx.iv_dma_addr, - hw_iv_size, NS_BIT); - if (ctx->cipher_mode == DRV_CIPHER_CTR) - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - else - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - set_cipher_mode(&desc[idx], ctx->cipher_mode); - idx++; - - /* Setup enc. key */ - hw_desc_init(&desc[idx]); - set_cipher_config0(&desc[idx], direct); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_flow_mode(&desc[idx], ctx->flow_mode); - if (ctx->flow_mode == S_DIN_to_AES) { - set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr, - ((ctx->enc_keylen == 24) ? CC_AES_KEY_SIZE_MAX : - ctx->enc_keylen), NS_BIT); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - } else { - set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr, - ctx->enc_keylen, NS_BIT); - set_key_size_des(&desc[idx], ctx->enc_keylen); - } - set_cipher_mode(&desc[idx], ctx->cipher_mode); - idx++; - - *seq_size = idx; -} - -static void cc_proc_cipher(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size, unsigned int data_flow_mode) -{ - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - int direct = req_ctx->gen_ctx.op_type; - unsigned int idx = *seq_size; - - if (req_ctx->cryptlen == 0) - return; /*null processing*/ - - cc_set_cipher_desc(req, desc, &idx); - cc_proc_cipher_desc(req, data_flow_mode, desc, &idx); - if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) { - /* We must wait for DMA to write all cipher */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - } - - *seq_size = idx; -} - -static void cc_set_hmac_desc(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ? - DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256; - unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ? - CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE; - unsigned int idx = *seq_size; - - /* Loading hash ipad xor key state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_din_type(&desc[idx], DMA_DLLI, - ctx->auth_state.hmac.ipad_opad_dma_addr, digest_size, - NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load init. digest len (64 bytes) */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_din_sram(&desc[idx], cc_digest_len_addr(ctx->drvdata, hash_mode), - HASH_LEN_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - *seq_size = idx; -} - -static void cc_set_xcbc_desc(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - unsigned int idx = *seq_size; - - /* Loading MAC state */ - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, CC_AES_BLOCK_SIZE); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* Setup XCBC MAC K1 */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - ctx->auth_state.xcbc.xcbc_keys_dma_addr, - AES_KEYSIZE_128, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* Setup XCBC MAC K2 */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - (ctx->auth_state.xcbc.xcbc_keys_dma_addr + - AES_KEYSIZE_128), AES_KEYSIZE_128, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* Setup XCBC MAC K3 */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - (ctx->auth_state.xcbc.xcbc_keys_dma_addr + - 2 * AES_KEYSIZE_128), AES_KEYSIZE_128, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE2); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - *seq_size = idx; -} - -static void cc_proc_header_desc(struct aead_request *req, - struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - unsigned int idx = *seq_size; - /* Hash associated data */ - if (req->assoclen > 0) - cc_set_assoc_desc(req, DIN_HASH, desc, &idx); - - /* Hash IV */ - *seq_size = idx; -} - -static void cc_proc_scheme_desc(struct aead_request *req, - struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct cc_aead_handle *aead_handle = ctx->drvdata->aead_handle; - unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ? - DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256; - unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ? - CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE; - unsigned int idx = *seq_size; - - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_dout_sram(&desc[idx], aead_handle->sram_workspace_addr, - HASH_LEN_SIZE); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE1); - set_cipher_do(&desc[idx], DO_PAD); - idx++; - - /* Get final ICV result */ - hw_desc_init(&desc[idx]); - set_dout_sram(&desc[idx], aead_handle->sram_workspace_addr, - digest_size); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN); - set_cipher_mode(&desc[idx], hash_mode); - idx++; - - /* Loading hash opad xor key state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_din_type(&desc[idx], DMA_DLLI, - (ctx->auth_state.hmac.ipad_opad_dma_addr + digest_size), - digest_size, NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load init. digest len (64 bytes) */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], hash_mode); - set_din_sram(&desc[idx], cc_digest_len_addr(ctx->drvdata, hash_mode), - HASH_LEN_SIZE); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Perform HASH update */ - hw_desc_init(&desc[idx]); - set_din_sram(&desc[idx], aead_handle->sram_workspace_addr, - digest_size); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - *seq_size = idx; -} - -static void cc_mlli_to_sram(struct aead_request *req, - struct cc_hw_desc desc[], unsigned int *seq_size) -{ - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - if (req_ctx->assoc_buff_type == CC_DMA_BUF_MLLI || - req_ctx->data_buff_type == CC_DMA_BUF_MLLI || - !req_ctx->is_single_pass) { - dev_dbg(dev, "Copy-to-sram: mlli_dma=%08x, mlli_size=%u\n", - (unsigned int)ctx->drvdata->mlli_sram_addr, - req_ctx->mlli_params.mlli_len); - /* Copy MLLI table host-to-sram */ - hw_desc_init(&desc[*seq_size]); - set_din_type(&desc[*seq_size], DMA_DLLI, - req_ctx->mlli_params.mlli_dma_addr, - req_ctx->mlli_params.mlli_len, NS_BIT); - set_dout_sram(&desc[*seq_size], - ctx->drvdata->mlli_sram_addr, - req_ctx->mlli_params.mlli_len); - set_flow_mode(&desc[*seq_size], BYPASS); - (*seq_size)++; - } -} - -static enum cc_flow_mode cc_get_data_flow(enum drv_crypto_direction direct, - enum cc_flow_mode setup_flow_mode, - bool is_single_pass) -{ - enum cc_flow_mode data_flow_mode; - - if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) { - if (setup_flow_mode == S_DIN_to_AES) - data_flow_mode = is_single_pass ? - AES_to_HASH_and_DOUT : DIN_AES_DOUT; - else - data_flow_mode = is_single_pass ? - DES_to_HASH_and_DOUT : DIN_DES_DOUT; - } else { /* Decrypt */ - if (setup_flow_mode == S_DIN_to_AES) - data_flow_mode = is_single_pass ? - AES_and_HASH : DIN_AES_DOUT; - else - data_flow_mode = is_single_pass ? - DES_and_HASH : DIN_DES_DOUT; - } - - return data_flow_mode; -} - -static void cc_hmac_authenc(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - int direct = req_ctx->gen_ctx.op_type; - unsigned int data_flow_mode = - cc_get_data_flow(direct, ctx->flow_mode, - req_ctx->is_single_pass); - - if (req_ctx->is_single_pass) { - /** - * Single-pass flow - */ - cc_set_hmac_desc(req, desc, seq_size); - cc_set_cipher_desc(req, desc, seq_size); - cc_proc_header_desc(req, desc, seq_size); - cc_proc_cipher_desc(req, data_flow_mode, desc, seq_size); - cc_proc_scheme_desc(req, desc, seq_size); - cc_proc_digest_desc(req, desc, seq_size); - return; - } - - /** - * Double-pass flow - * Fallback for unsupported single-pass modes, - * i.e. using assoc. data of non-word-multiple - */ - if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) { - /* encrypt first.. */ - cc_proc_cipher(req, desc, seq_size, data_flow_mode); - /* authenc after..*/ - cc_set_hmac_desc(req, desc, seq_size); - cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct); - cc_proc_scheme_desc(req, desc, seq_size); - cc_proc_digest_desc(req, desc, seq_size); - - } else { /*DECRYPT*/ - /* authenc first..*/ - cc_set_hmac_desc(req, desc, seq_size); - cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct); - cc_proc_scheme_desc(req, desc, seq_size); - /* decrypt after.. */ - cc_proc_cipher(req, desc, seq_size, data_flow_mode); - /* read the digest result with setting the completion bit - * must be after the cipher operation - */ - cc_proc_digest_desc(req, desc, seq_size); - } -} - -static void -cc_xcbc_authenc(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - int direct = req_ctx->gen_ctx.op_type; - unsigned int data_flow_mode = - cc_get_data_flow(direct, ctx->flow_mode, - req_ctx->is_single_pass); - - if (req_ctx->is_single_pass) { - /** - * Single-pass flow - */ - cc_set_xcbc_desc(req, desc, seq_size); - cc_set_cipher_desc(req, desc, seq_size); - cc_proc_header_desc(req, desc, seq_size); - cc_proc_cipher_desc(req, data_flow_mode, desc, seq_size); - cc_proc_digest_desc(req, desc, seq_size); - return; - } - - /** - * Double-pass flow - * Fallback for unsupported single-pass modes, - * i.e. using assoc. data of non-word-multiple - */ - if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) { - /* encrypt first.. */ - cc_proc_cipher(req, desc, seq_size, data_flow_mode); - /* authenc after.. */ - cc_set_xcbc_desc(req, desc, seq_size); - cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct); - cc_proc_digest_desc(req, desc, seq_size); - } else { /*DECRYPT*/ - /* authenc first.. */ - cc_set_xcbc_desc(req, desc, seq_size); - cc_proc_authen_desc(req, DIN_HASH, desc, seq_size, direct); - /* decrypt after..*/ - cc_proc_cipher(req, desc, seq_size, data_flow_mode); - /* read the digest result with setting the completion bit - * must be after the cipher operation - */ - cc_proc_digest_desc(req, desc, seq_size); - } -} - -static int validate_data_size(struct cc_aead_ctx *ctx, - enum drv_crypto_direction direct, - struct aead_request *req) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - struct device *dev = drvdata_to_dev(ctx->drvdata); - unsigned int assoclen = req->assoclen; - unsigned int cipherlen = (direct == DRV_CRYPTO_DIRECTION_DECRYPT) ? - (req->cryptlen - ctx->authsize) : req->cryptlen; - - if (direct == DRV_CRYPTO_DIRECTION_DECRYPT && - req->cryptlen < ctx->authsize) - goto data_size_err; - - areq_ctx->is_single_pass = true; /*defaulted to fast flow*/ - - switch (ctx->flow_mode) { - case S_DIN_to_AES: - if (ctx->cipher_mode == DRV_CIPHER_CBC && - !IS_ALIGNED(cipherlen, AES_BLOCK_SIZE)) - goto data_size_err; - if (ctx->cipher_mode == DRV_CIPHER_CCM) - break; - if (ctx->cipher_mode == DRV_CIPHER_GCTR) { - if (areq_ctx->plaintext_authenticate_only) - areq_ctx->is_single_pass = false; - break; - } - - if (!IS_ALIGNED(assoclen, sizeof(u32))) - areq_ctx->is_single_pass = false; - - if (ctx->cipher_mode == DRV_CIPHER_CTR && - !IS_ALIGNED(cipherlen, sizeof(u32))) - areq_ctx->is_single_pass = false; - - break; - case S_DIN_to_DES: - if (!IS_ALIGNED(cipherlen, DES_BLOCK_SIZE)) - goto data_size_err; - if (!IS_ALIGNED(assoclen, DES_BLOCK_SIZE)) - areq_ctx->is_single_pass = false; - break; - default: - dev_err(dev, "Unexpected flow mode (%d)\n", ctx->flow_mode); - goto data_size_err; - } - - return 0; - -data_size_err: - return -EINVAL; -} - -static unsigned int format_ccm_a0(u8 *pa0_buff, u32 header_size) -{ - unsigned int len = 0; - - if (header_size == 0) - return 0; - - if (header_size < ((1UL << 16) - (1UL << 8))) { - len = 2; - - pa0_buff[0] = (header_size >> 8) & 0xFF; - pa0_buff[1] = header_size & 0xFF; - } else { - len = 6; - - pa0_buff[0] = 0xFF; - pa0_buff[1] = 0xFE; - pa0_buff[2] = (header_size >> 24) & 0xFF; - pa0_buff[3] = (header_size >> 16) & 0xFF; - pa0_buff[4] = (header_size >> 8) & 0xFF; - pa0_buff[5] = header_size & 0xFF; - } - - return len; -} - -static int set_msg_len(u8 *block, unsigned int msglen, unsigned int csize) -{ - __be32 data; - - memset(block, 0, csize); - block += csize; - - if (csize >= 4) - csize = 4; - else if (msglen > (1 << (8 * csize))) - return -EOVERFLOW; - - data = cpu_to_be32(msglen); - memcpy(block - csize, (u8 *)&data + 4 - csize, csize); - - return 0; -} - -static int cc_ccm(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - unsigned int idx = *seq_size; - unsigned int cipher_flow_mode; - dma_addr_t mac_result; - - if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) { - cipher_flow_mode = AES_to_HASH_and_DOUT; - mac_result = req_ctx->mac_buf_dma_addr; - } else { /* Encrypt */ - cipher_flow_mode = AES_and_HASH; - mac_result = req_ctx->icv_dma_addr; - } - - /* load key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CTR); - set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr, - ((ctx->enc_keylen == 24) ? CC_AES_KEY_SIZE_MAX : - ctx->enc_keylen), NS_BIT); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* load ctr state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CTR); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_din_type(&desc[idx], DMA_DLLI, - req_ctx->gen_ctx.iv_dma_addr, AES_BLOCK_SIZE, NS_BIT); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* load MAC key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC); - set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr, - ((ctx->enc_keylen == 24) ? CC_AES_KEY_SIZE_MAX : - ctx->enc_keylen), NS_BIT); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* load MAC state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr, - AES_BLOCK_SIZE, NS_BIT); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* process assoc data */ - if (req->assoclen > 0) { - cc_set_assoc_desc(req, DIN_HASH, desc, &idx); - } else { - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - sg_dma_address(&req_ctx->ccm_adata_sg), - AES_BLOCK_SIZE + req_ctx->ccm_hdr_size, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - } - - /* process the cipher */ - if (req_ctx->cryptlen) - cc_proc_cipher_desc(req, cipher_flow_mode, desc, &idx); - - /* Read temporal MAC */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CBC_MAC); - set_dout_dlli(&desc[idx], req_ctx->mac_buf_dma_addr, ctx->authsize, - NS_BIT, 0); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_aes_not_hash_mode(&desc[idx]); - idx++; - - /* load AES-CTR state (for last MAC calculation)*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_CTR); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->ccm_iv0_dma_addr, - AES_BLOCK_SIZE, NS_BIT); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* encrypt the "T" value and store MAC in mac_state */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr, - ctx->authsize, NS_BIT); - set_dout_dlli(&desc[idx], mac_result, ctx->authsize, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - *seq_size = idx; - return 0; -} - -static int config_ccm_adata(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - //unsigned int size_of_a = 0, rem_a_size = 0; - unsigned int lp = req->iv[0]; - /* Note: The code assume that req->iv[0] already contains the value - * of L' of RFC3610 - */ - unsigned int l = lp + 1; /* This is L' of RFC 3610. */ - unsigned int m = ctx->authsize; /* This is M' of RFC 3610. */ - u8 *b0 = req_ctx->ccm_config + CCM_B0_OFFSET; - u8 *a0 = req_ctx->ccm_config + CCM_A0_OFFSET; - u8 *ctr_count_0 = req_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET; - unsigned int cryptlen = (req_ctx->gen_ctx.op_type == - DRV_CRYPTO_DIRECTION_ENCRYPT) ? - req->cryptlen : - (req->cryptlen - ctx->authsize); - int rc; - - memset(req_ctx->mac_buf, 0, AES_BLOCK_SIZE); - memset(req_ctx->ccm_config, 0, AES_BLOCK_SIZE * 3); - - /* taken from crypto/ccm.c */ - /* 2 <= L <= 8, so 1 <= L' <= 7. */ - if (l < 2 || l > 8) { - dev_err(dev, "illegal iv value %X\n", req->iv[0]); - return -EINVAL; - } - memcpy(b0, req->iv, AES_BLOCK_SIZE); - - /* format control info per RFC 3610 and - * NIST Special Publication 800-38C - */ - *b0 |= (8 * ((m - 2) / 2)); - if (req->assoclen > 0) - *b0 |= 64; /* Enable bit 6 if Adata exists. */ - - rc = set_msg_len(b0 + 16 - l, cryptlen, l); /* Write L'. */ - if (rc) { - dev_err(dev, "message len overflow detected"); - return rc; - } - /* END of "taken from crypto/ccm.c" */ - - /* l(a) - size of associated data. */ - req_ctx->ccm_hdr_size = format_ccm_a0(a0, req->assoclen); - - memset(req->iv + 15 - req->iv[0], 0, req->iv[0] + 1); - req->iv[15] = 1; - - memcpy(ctr_count_0, req->iv, AES_BLOCK_SIZE); - ctr_count_0[15] = 0; - - return 0; -} - -static void cc_proc_rfc4309_ccm(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - - /* L' */ - memset(areq_ctx->ctr_iv, 0, AES_BLOCK_SIZE); - /* For RFC 4309, always use 4 bytes for message length - * (at most 2^32-1 bytes). - */ - areq_ctx->ctr_iv[0] = 3; - - /* In RFC 4309 there is an 11-bytes nonce+IV part, - * that we build here. - */ - memcpy(areq_ctx->ctr_iv + CCM_BLOCK_NONCE_OFFSET, ctx->ctr_nonce, - CCM_BLOCK_NONCE_SIZE); - memcpy(areq_ctx->ctr_iv + CCM_BLOCK_IV_OFFSET, req->iv, - CCM_BLOCK_IV_SIZE); - req->iv = areq_ctx->ctr_iv; - req->assoclen -= CCM_BLOCK_IV_SIZE; -} - -static void cc_set_ghash_desc(struct aead_request *req, - struct cc_hw_desc desc[], unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - unsigned int idx = *seq_size; - - /* load key to AES*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_ECB); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr, - ctx->enc_keylen, NS_BIT); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* process one zero block to generate hkey */ - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x0, AES_BLOCK_SIZE); - set_dout_dlli(&desc[idx], req_ctx->hkey_dma_addr, AES_BLOCK_SIZE, - NS_BIT, 0); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - /* Memory Barrier */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* Load GHASH subkey */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->hkey_dma_addr, - AES_BLOCK_SIZE, NS_BIT); - set_dout_no_dma(&desc[idx], 0, 0, 1); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Configure Hash Engine to work with GHASH. - * Since it was not possible to extend HASH submodes to add GHASH, - * The following command is necessary in order to - * select GHASH (according to HW designers) - */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_cipher_do(&desc[idx], 1); //1=AES_SK RKEK - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Load GHASH initial STATE (which is 0). (for any hash there is an - * initial state) - */ - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x0, AES_BLOCK_SIZE); - set_dout_no_dma(&desc[idx], 0, 0, 1); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_aes_not_hash_mode(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - *seq_size = idx; -} - -static void cc_set_gctr_desc(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - unsigned int idx = *seq_size; - - /* load key to AES*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_din_type(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr, - ctx->enc_keylen, NS_BIT); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - if (req_ctx->cryptlen && !req_ctx->plaintext_authenticate_only) { - /* load AES/CTR initial CTR value inc by 2*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_din_type(&desc[idx], DMA_DLLI, - req_ctx->gcm_iv_inc2_dma_addr, AES_BLOCK_SIZE, - NS_BIT); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - } - - *seq_size = idx; -} - -static void cc_proc_gcm_result(struct aead_request *req, - struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - dma_addr_t mac_result; - unsigned int idx = *seq_size; - - if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) { - mac_result = req_ctx->mac_buf_dma_addr; - } else { /* Encrypt */ - mac_result = req_ctx->icv_dma_addr; - } - - /* process(ghash) gcm_block_len */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->gcm_block_len_dma_addr, - AES_BLOCK_SIZE, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Store GHASH state after GHASH(Associated Data + Cipher +LenBlock) */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_HASH_HW_GHASH); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_dlli(&desc[idx], req_ctx->mac_buf_dma_addr, AES_BLOCK_SIZE, - NS_BIT, 0); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_aes_not_hash_mode(&desc[idx]); - - idx++; - - /* load AES/CTR initial CTR value inc by 1*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_key_size_aes(&desc[idx], ctx->enc_keylen); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->gcm_iv_inc1_dma_addr, - AES_BLOCK_SIZE, NS_BIT); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Memory Barrier */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* process GCTR on stored GHASH and store MAC in mac_state*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_GCTR); - set_din_type(&desc[idx], DMA_DLLI, req_ctx->mac_buf_dma_addr, - AES_BLOCK_SIZE, NS_BIT); - set_dout_dlli(&desc[idx], mac_result, ctx->authsize, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - *seq_size = idx; -} - -static int cc_gcm(struct aead_request *req, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - unsigned int cipher_flow_mode; - - if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) { - cipher_flow_mode = AES_and_HASH; - } else { /* Encrypt */ - cipher_flow_mode = AES_to_HASH_and_DOUT; - } - - //in RFC4543 no data to encrypt. just copy data from src to dest. - if (req_ctx->plaintext_authenticate_only) { - cc_proc_cipher_desc(req, BYPASS, desc, seq_size); - cc_set_ghash_desc(req, desc, seq_size); - /* process(ghash) assoc data */ - cc_set_assoc_desc(req, DIN_HASH, desc, seq_size); - cc_set_gctr_desc(req, desc, seq_size); - cc_proc_gcm_result(req, desc, seq_size); - return 0; - } - - // for gcm and rfc4106. - cc_set_ghash_desc(req, desc, seq_size); - /* process(ghash) assoc data */ - if (req->assoclen > 0) - cc_set_assoc_desc(req, DIN_HASH, desc, seq_size); - cc_set_gctr_desc(req, desc, seq_size); - /* process(gctr+ghash) */ - if (req_ctx->cryptlen) - cc_proc_cipher_desc(req, cipher_flow_mode, desc, seq_size); - cc_proc_gcm_result(req, desc, seq_size); - - return 0; -} - -static int config_gcm_context(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *req_ctx = aead_request_ctx(req); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - unsigned int cryptlen = (req_ctx->gen_ctx.op_type == - DRV_CRYPTO_DIRECTION_ENCRYPT) ? - req->cryptlen : - (req->cryptlen - ctx->authsize); - __be32 counter = cpu_to_be32(2); - - dev_dbg(dev, "%s() cryptlen = %d, req->assoclen = %d ctx->authsize = %d\n", - __func__, cryptlen, req->assoclen, ctx->authsize); - - memset(req_ctx->hkey, 0, AES_BLOCK_SIZE); - - memset(req_ctx->mac_buf, 0, AES_BLOCK_SIZE); - - memcpy(req->iv + 12, &counter, 4); - memcpy(req_ctx->gcm_iv_inc2, req->iv, 16); - - counter = cpu_to_be32(1); - memcpy(req->iv + 12, &counter, 4); - memcpy(req_ctx->gcm_iv_inc1, req->iv, 16); - - if (!req_ctx->plaintext_authenticate_only) { - __be64 temp64; - - temp64 = cpu_to_be64(req->assoclen * 8); - memcpy(&req_ctx->gcm_len_block.len_a, &temp64, sizeof(temp64)); - temp64 = cpu_to_be64(cryptlen * 8); - memcpy(&req_ctx->gcm_len_block.len_c, &temp64, 8); - } else { - /* rfc4543=> all data(AAD,IV,Plain) are considered additional - * data that is nothing is encrypted. - */ - __be64 temp64; - - temp64 = cpu_to_be64((req->assoclen + GCM_BLOCK_RFC4_IV_SIZE + - cryptlen) * 8); - memcpy(&req_ctx->gcm_len_block.len_a, &temp64, sizeof(temp64)); - temp64 = 0; - memcpy(&req_ctx->gcm_len_block.len_c, &temp64, 8); - } - - return 0; -} - -static void cc_proc_rfc4_gcm(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - - memcpy(areq_ctx->ctr_iv + GCM_BLOCK_RFC4_NONCE_OFFSET, - ctx->ctr_nonce, GCM_BLOCK_RFC4_NONCE_SIZE); - memcpy(areq_ctx->ctr_iv + GCM_BLOCK_RFC4_IV_OFFSET, req->iv, - GCM_BLOCK_RFC4_IV_SIZE); - req->iv = areq_ctx->ctr_iv; - req->assoclen -= GCM_BLOCK_RFC4_IV_SIZE; -} - -static int cc_proc_aead(struct aead_request *req, - enum drv_crypto_direction direct) -{ - int rc = 0; - int seq_len = 0; - struct cc_hw_desc desc[MAX_AEAD_PROCESS_SEQ]; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct cc_crypto_req cc_req = {}; - - dev_dbg(dev, "%s context=%p req=%p iv=%p src=%p src_ofs=%d dst=%p dst_ofs=%d cryptolen=%d\n", - ((direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? "Enc" : "Dec"), - ctx, req, req->iv, sg_virt(req->src), req->src->offset, - sg_virt(req->dst), req->dst->offset, req->cryptlen); - - /* STAT_PHASE_0: Init and sanity checks */ - - /* Check data length according to mode */ - if (validate_data_size(ctx, direct, req)) { - dev_err(dev, "Unsupported crypt/assoc len %d/%d.\n", - req->cryptlen, req->assoclen); - crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN); - return -EINVAL; - } - - /* Setup DX request structure */ - cc_req.user_cb = (void *)cc_aead_complete; - cc_req.user_arg = (void *)req; - - /* Setup request context */ - areq_ctx->gen_ctx.op_type = direct; - areq_ctx->req_authsize = ctx->authsize; - areq_ctx->cipher_mode = ctx->cipher_mode; - - /* STAT_PHASE_1: Map buffers */ - - if (ctx->cipher_mode == DRV_CIPHER_CTR) { - /* Build CTR IV - Copy nonce from last 4 bytes in - * CTR key to first 4 bytes in CTR IV - */ - memcpy(areq_ctx->ctr_iv, ctx->ctr_nonce, - CTR_RFC3686_NONCE_SIZE); - if (!areq_ctx->backup_giv) /*User none-generated IV*/ - memcpy(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE, - req->iv, CTR_RFC3686_IV_SIZE); - /* Initialize counter portion of counter block */ - *(__be32 *)(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE + - CTR_RFC3686_IV_SIZE) = cpu_to_be32(1); - - /* Replace with counter iv */ - req->iv = areq_ctx->ctr_iv; - areq_ctx->hw_iv_size = CTR_RFC3686_BLOCK_SIZE; - } else if ((ctx->cipher_mode == DRV_CIPHER_CCM) || - (ctx->cipher_mode == DRV_CIPHER_GCTR)) { - areq_ctx->hw_iv_size = AES_BLOCK_SIZE; - if (areq_ctx->ctr_iv != req->iv) { - memcpy(areq_ctx->ctr_iv, req->iv, - crypto_aead_ivsize(tfm)); - req->iv = areq_ctx->ctr_iv; - } - } else { - areq_ctx->hw_iv_size = crypto_aead_ivsize(tfm); - } - - if (ctx->cipher_mode == DRV_CIPHER_CCM) { - rc = config_ccm_adata(req); - if (rc) { - dev_dbg(dev, "config_ccm_adata() returned with a failure %d!", - rc); - goto exit; - } - } else { - areq_ctx->ccm_hdr_size = ccm_header_size_null; - } - - if (ctx->cipher_mode == DRV_CIPHER_GCTR) { - rc = config_gcm_context(req); - if (rc) { - dev_dbg(dev, "config_gcm_context() returned with a failure %d!", - rc); - goto exit; - } - } - - rc = cc_map_aead_request(ctx->drvdata, req); - if (rc) { - dev_err(dev, "map_request() failed\n"); - goto exit; - } - - /* do we need to generate IV? */ - if (areq_ctx->backup_giv) { - /* set the DMA mapped IV address*/ - if (ctx->cipher_mode == DRV_CIPHER_CTR) { - cc_req.ivgen_dma_addr[0] = - areq_ctx->gen_ctx.iv_dma_addr + - CTR_RFC3686_NONCE_SIZE; - cc_req.ivgen_dma_addr_len = 1; - } else if (ctx->cipher_mode == DRV_CIPHER_CCM) { - /* In ccm, the IV needs to exist both inside B0 and - * inside the counter.It is also copied to iv_dma_addr - * for other reasons (like returning it to the user). - * So, using 3 (identical) IV outputs. - */ - cc_req.ivgen_dma_addr[0] = - areq_ctx->gen_ctx.iv_dma_addr + - CCM_BLOCK_IV_OFFSET; - cc_req.ivgen_dma_addr[1] = - sg_dma_address(&areq_ctx->ccm_adata_sg) + - CCM_B0_OFFSET + CCM_BLOCK_IV_OFFSET; - cc_req.ivgen_dma_addr[2] = - sg_dma_address(&areq_ctx->ccm_adata_sg) + - CCM_CTR_COUNT_0_OFFSET + CCM_BLOCK_IV_OFFSET; - cc_req.ivgen_dma_addr_len = 3; - } else { - cc_req.ivgen_dma_addr[0] = - areq_ctx->gen_ctx.iv_dma_addr; - cc_req.ivgen_dma_addr_len = 1; - } - - /* set the IV size (8/16 B long)*/ - cc_req.ivgen_size = crypto_aead_ivsize(tfm); - } - - /* STAT_PHASE_2: Create sequence */ - - /* Load MLLI tables to SRAM if necessary */ - cc_mlli_to_sram(req, desc, &seq_len); - - /*TODO: move seq len by reference */ - switch (ctx->auth_mode) { - case DRV_HASH_SHA1: - case DRV_HASH_SHA256: - cc_hmac_authenc(req, desc, &seq_len); - break; - case DRV_HASH_XCBC_MAC: - cc_xcbc_authenc(req, desc, &seq_len); - break; - case DRV_HASH_NULL: - if (ctx->cipher_mode == DRV_CIPHER_CCM) - cc_ccm(req, desc, &seq_len); - if (ctx->cipher_mode == DRV_CIPHER_GCTR) - cc_gcm(req, desc, &seq_len); - break; - default: - dev_err(dev, "Unsupported authenc (%d)\n", ctx->auth_mode); - cc_unmap_aead_request(dev, req); - rc = -ENOTSUPP; - goto exit; - } - - /* STAT_PHASE_3: Lock HW and push sequence */ - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, seq_len, &req->base); - - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_aead_request(dev, req); - } - -exit: - return rc; -} - -static int cc_aead_encrypt(struct aead_request *req) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc; - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - areq_ctx->is_gcm4543 = false; - - areq_ctx->plaintext_authenticate_only = false; - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; - - return rc; -} - -static int cc_rfc4309_ccm_encrypt(struct aead_request *req) -{ - /* Very similar to cc_aead_encrypt() above. */ - - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - int rc = -EINVAL; - - if (!valid_assoclen(req)) { - dev_err(dev, "invalid Assoclen:%u\n", req->assoclen); - goto out; - } - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - areq_ctx->is_gcm4543 = true; - - cc_proc_rfc4309_ccm(req); - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; -out: - return rc; -} - -static int cc_aead_decrypt(struct aead_request *req) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc; - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - areq_ctx->is_gcm4543 = false; - - areq_ctx->plaintext_authenticate_only = false; - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; - - return rc; -} - -static int cc_rfc4309_ccm_decrypt(struct aead_request *req) -{ - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc = -EINVAL; - - if (!valid_assoclen(req)) { - dev_err(dev, "invalid Assoclen:%u\n", req->assoclen); - goto out; - } - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - - areq_ctx->is_gcm4543 = true; - cc_proc_rfc4309_ccm(req); - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; - -out: - return rc; -} - -static int cc_rfc4106_gcm_setkey(struct crypto_aead *tfm, const u8 *key, - unsigned int keylen) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "%s() keylen %d, key %p\n", __func__, keylen, key); - - if (keylen < 4) - return -EINVAL; - - keylen -= 4; - memcpy(ctx->ctr_nonce, key + keylen, 4); - - return cc_aead_setkey(tfm, key, keylen); -} - -static int cc_rfc4543_gcm_setkey(struct crypto_aead *tfm, const u8 *key, - unsigned int keylen) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "%s() keylen %d, key %p\n", __func__, keylen, key); - - if (keylen < 4) - return -EINVAL; - - keylen -= 4; - memcpy(ctx->ctr_nonce, key + keylen, 4); - - return cc_aead_setkey(tfm, key, keylen); -} - -static int cc_gcm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - switch (authsize) { - case 4: - case 8: - case 12: - case 13: - case 14: - case 15: - case 16: - break; - default: - return -EINVAL; - } - - return cc_aead_setauthsize(authenc, authsize); -} - -static int cc_rfc4106_gcm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(authenc); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "authsize %d\n", authsize); - - switch (authsize) { - case 8: - case 12: - case 16: - break; - default: - return -EINVAL; - } - - return cc_aead_setauthsize(authenc, authsize); -} - -static int cc_rfc4543_gcm_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - struct cc_aead_ctx *ctx = crypto_aead_ctx(authenc); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "authsize %d\n", authsize); - - if (authsize != 16) - return -EINVAL; - - return cc_aead_setauthsize(authenc, authsize); -} - -static int cc_rfc4106_gcm_encrypt(struct aead_request *req) -{ - /* Very similar to cc_aead_encrypt() above. */ - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc = -EINVAL; - - if (!valid_assoclen(req)) { - dev_err(dev, "invalid Assoclen:%u\n", req->assoclen); - goto out; - } - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - - areq_ctx->plaintext_authenticate_only = false; - - cc_proc_rfc4_gcm(req); - areq_ctx->is_gcm4543 = true; - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; -out: - return rc; -} - -static int cc_rfc4543_gcm_encrypt(struct aead_request *req) -{ - /* Very similar to cc_aead_encrypt() above. */ - - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc; - - //plaintext is not encryped with rfc4543 - areq_ctx->plaintext_authenticate_only = true; - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - - cc_proc_rfc4_gcm(req); - areq_ctx->is_gcm4543 = true; - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_ENCRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; - - return rc; -} - -static int cc_rfc4106_gcm_decrypt(struct aead_request *req) -{ - /* Very similar to cc_aead_decrypt() above. */ - - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc = -EINVAL; - - if (!valid_assoclen(req)) { - dev_err(dev, "invalid Assoclen:%u\n", req->assoclen); - goto out; - } - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - - areq_ctx->plaintext_authenticate_only = false; - - cc_proc_rfc4_gcm(req); - areq_ctx->is_gcm4543 = true; - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; -out: - return rc; -} - -static int cc_rfc4543_gcm_decrypt(struct aead_request *req) -{ - /* Very similar to cc_aead_decrypt() above. */ - - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc; - - //plaintext is not decryped with rfc4543 - areq_ctx->plaintext_authenticate_only = true; - - /* No generated IV required */ - areq_ctx->backup_iv = req->iv; - areq_ctx->backup_giv = NULL; - - cc_proc_rfc4_gcm(req); - areq_ctx->is_gcm4543 = true; - - rc = cc_proc_aead(req, DRV_CRYPTO_DIRECTION_DECRYPT); - if (rc != -EINPROGRESS && rc != -EBUSY) - req->iv = areq_ctx->backup_iv; - - return rc; -} - -/* DX Block aead alg */ -static struct cc_alg_template aead_algs[] = { - { - .name = "authenc(hmac(sha1),cbc(aes))", - .driver_name = "authenc-hmac-sha1-cbc-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_SHA1, - }, - { - .name = "authenc(hmac(sha1),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha1-cbc-des3-dx", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_DES, - .auth_mode = DRV_HASH_SHA1, - }, - { - .name = "authenc(hmac(sha256),cbc(aes))", - .driver_name = "authenc-hmac-sha256-cbc-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_SHA256, - }, - { - .name = "authenc(hmac(sha256),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha256-cbc-des3-dx", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_DES, - .auth_mode = DRV_HASH_SHA256, - }, - { - .name = "authenc(xcbc(aes),cbc(aes))", - .driver_name = "authenc-xcbc-aes-cbc-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_XCBC_MAC, - }, - { - .name = "authenc(hmac(sha1),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha1-rfc3686-ctr-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, - .cipher_mode = DRV_CIPHER_CTR, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_SHA1, - }, - { - .name = "authenc(hmac(sha256),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha256-rfc3686-ctr-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, - .cipher_mode = DRV_CIPHER_CTR, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_SHA256, - }, - { - .name = "authenc(xcbc(aes),rfc3686(ctr(aes)))", - .driver_name = "authenc-xcbc-aes-rfc3686-ctr-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_aead_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CTR, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_XCBC_MAC, - }, - { - .name = "ccm(aes)", - .driver_name = "ccm-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_ccm_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CCM, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_NULL, - }, - { - .name = "rfc4309(ccm(aes))", - .driver_name = "rfc4309-ccm-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_rfc4309_ccm_setkey, - .setauthsize = cc_rfc4309_ccm_setauthsize, - .encrypt = cc_rfc4309_ccm_encrypt, - .decrypt = cc_rfc4309_ccm_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = CCM_BLOCK_IV_SIZE, - .maxauthsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CCM, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_NULL, - }, - { - .name = "gcm(aes)", - .driver_name = "gcm-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_aead_setkey, - .setauthsize = cc_gcm_setauthsize, - .encrypt = cc_aead_encrypt, - .decrypt = cc_aead_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = 12, - .maxauthsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_GCTR, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_NULL, - }, - { - .name = "rfc4106(gcm(aes))", - .driver_name = "rfc4106-gcm-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_rfc4106_gcm_setkey, - .setauthsize = cc_rfc4106_gcm_setauthsize, - .encrypt = cc_rfc4106_gcm_encrypt, - .decrypt = cc_rfc4106_gcm_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = GCM_BLOCK_RFC4_IV_SIZE, - .maxauthsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_GCTR, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_NULL, - }, - { - .name = "rfc4543(gcm(aes))", - .driver_name = "rfc4543-gcm-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = cc_rfc4543_gcm_setkey, - .setauthsize = cc_rfc4543_gcm_setauthsize, - .encrypt = cc_rfc4543_gcm_encrypt, - .decrypt = cc_rfc4543_gcm_decrypt, - .init = cc_aead_init, - .exit = cc_aead_exit, - .ivsize = GCM_BLOCK_RFC4_IV_SIZE, - .maxauthsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_GCTR, - .flow_mode = S_DIN_to_AES, - .auth_mode = DRV_HASH_NULL, - }, -}; - -static struct cc_crypto_alg *cc_create_aead_alg(struct cc_alg_template *tmpl, - struct device *dev) -{ - struct cc_crypto_alg *t_alg; - struct aead_alg *alg; - - t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); - if (!t_alg) - return ERR_PTR(-ENOMEM); - - alg = &tmpl->template_aead; - - snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); - snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->driver_name); - alg->base.cra_module = THIS_MODULE; - alg->base.cra_priority = CC_CRA_PRIO; - - alg->base.cra_ctxsize = sizeof(struct cc_aead_ctx); - alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - tmpl->type; - alg->init = cc_aead_init; - alg->exit = cc_aead_exit; - - t_alg->aead_alg = *alg; - - t_alg->cipher_mode = tmpl->cipher_mode; - t_alg->flow_mode = tmpl->flow_mode; - t_alg->auth_mode = tmpl->auth_mode; - - return t_alg; -} - -int cc_aead_free(struct cc_drvdata *drvdata) -{ - struct cc_crypto_alg *t_alg, *n; - struct cc_aead_handle *aead_handle = - (struct cc_aead_handle *)drvdata->aead_handle; - - if (aead_handle) { - /* Remove registered algs */ - list_for_each_entry_safe(t_alg, n, &aead_handle->aead_list, - entry) { - crypto_unregister_aead(&t_alg->aead_alg); - list_del(&t_alg->entry); - kfree(t_alg); - } - kfree(aead_handle); - drvdata->aead_handle = NULL; - } - - return 0; -} - -int cc_aead_alloc(struct cc_drvdata *drvdata) -{ - struct cc_aead_handle *aead_handle; - struct cc_crypto_alg *t_alg; - int rc = -ENOMEM; - int alg; - struct device *dev = drvdata_to_dev(drvdata); - - aead_handle = kmalloc(sizeof(*aead_handle), GFP_KERNEL); - if (!aead_handle) { - rc = -ENOMEM; - goto fail0; - } - - INIT_LIST_HEAD(&aead_handle->aead_list); - drvdata->aead_handle = aead_handle; - - aead_handle->sram_workspace_addr = cc_sram_alloc(drvdata, - MAX_HMAC_DIGEST_SIZE); - - if (aead_handle->sram_workspace_addr == NULL_SRAM_ADDR) { - dev_err(dev, "SRAM pool exhausted\n"); - rc = -ENOMEM; - goto fail1; - } - - /* Linux crypto */ - for (alg = 0; alg < ARRAY_SIZE(aead_algs); alg++) { - t_alg = cc_create_aead_alg(&aead_algs[alg], dev); - if (IS_ERR(t_alg)) { - rc = PTR_ERR(t_alg); - dev_err(dev, "%s alg allocation failed\n", - aead_algs[alg].driver_name); - goto fail1; - } - t_alg->drvdata = drvdata; - rc = crypto_register_aead(&t_alg->aead_alg); - if (rc) { - dev_err(dev, "%s alg registration failed\n", - t_alg->aead_alg.base.cra_driver_name); - goto fail2; - } else { - list_add_tail(&t_alg->entry, &aead_handle->aead_list); - dev_dbg(dev, "Registered %s\n", - t_alg->aead_alg.base.cra_driver_name); - } - } - - return 0; - -fail2: - kfree(t_alg); -fail1: - cc_aead_free(drvdata); -fail0: - return rc; -} diff --git a/drivers/staging/ccree/cc_aead.h b/drivers/staging/ccree/cc_aead.h deleted file mode 100644 index 5edf3b351fa4..000000000000 --- a/drivers/staging/ccree/cc_aead.h +++ /dev/null @@ -1,109 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -/* \file cc_aead.h - * ARM CryptoCell AEAD Crypto API - */ - -#ifndef __CC_AEAD_H__ -#define __CC_AEAD_H__ - -#include <linux/kernel.h> -#include <crypto/algapi.h> -#include <crypto/ctr.h> - -/* mac_cmp - HW writes 8 B but all bytes hold the same value */ -#define ICV_CMP_SIZE 8 -#define CCM_CONFIG_BUF_SIZE (AES_BLOCK_SIZE * 3) -#define MAX_MAC_SIZE SHA256_DIGEST_SIZE - -/* defines for AES GCM configuration buffer */ -#define GCM_BLOCK_LEN_SIZE 8 - -#define GCM_BLOCK_RFC4_IV_OFFSET 4 -#define GCM_BLOCK_RFC4_IV_SIZE 8 /* IV size for rfc's */ -#define GCM_BLOCK_RFC4_NONCE_OFFSET 0 -#define GCM_BLOCK_RFC4_NONCE_SIZE 4 - -/* Offsets into AES CCM configuration buffer */ -#define CCM_B0_OFFSET 0 -#define CCM_A0_OFFSET 16 -#define CCM_CTR_COUNT_0_OFFSET 32 -/* CCM B0 and CTR_COUNT constants. */ -#define CCM_BLOCK_NONCE_OFFSET 1 /* Nonce offset inside B0 and CTR_COUNT */ -#define CCM_BLOCK_NONCE_SIZE 3 /* Nonce size inside B0 and CTR_COUNT */ -#define CCM_BLOCK_IV_OFFSET 4 /* IV offset inside B0 and CTR_COUNT */ -#define CCM_BLOCK_IV_SIZE 8 /* IV size inside B0 and CTR_COUNT */ - -enum aead_ccm_header_size { - ccm_header_size_null = -1, - ccm_header_size_zero = 0, - ccm_header_size_2 = 2, - ccm_header_size_6 = 6, - ccm_header_size_max = S32_MAX -}; - -struct aead_req_ctx { - /* Allocate cache line although only 4 bytes are needed to - * assure next field falls @ cache line - * Used for both: digest HW compare and CCM/GCM MAC value - */ - u8 mac_buf[MAX_MAC_SIZE] ____cacheline_aligned; - u8 ctr_iv[AES_BLOCK_SIZE] ____cacheline_aligned; - - //used in gcm - u8 gcm_iv_inc1[AES_BLOCK_SIZE] ____cacheline_aligned; - u8 gcm_iv_inc2[AES_BLOCK_SIZE] ____cacheline_aligned; - u8 hkey[AES_BLOCK_SIZE] ____cacheline_aligned; - struct { - u8 len_a[GCM_BLOCK_LEN_SIZE] ____cacheline_aligned; - u8 len_c[GCM_BLOCK_LEN_SIZE]; - } gcm_len_block; - - u8 ccm_config[CCM_CONFIG_BUF_SIZE] ____cacheline_aligned; - /* HW actual size input */ - unsigned int hw_iv_size ____cacheline_aligned; - /* used to prevent cache coherence problem */ - u8 backup_mac[MAX_MAC_SIZE]; - u8 *backup_iv; /*store iv for generated IV flow*/ - u8 *backup_giv; /*store iv for rfc3686(ctr) flow*/ - dma_addr_t mac_buf_dma_addr; /* internal ICV DMA buffer */ - /* buffer for internal ccm configurations */ - dma_addr_t ccm_iv0_dma_addr; - dma_addr_t icv_dma_addr; /* Phys. address of ICV */ - - //used in gcm - /* buffer for internal gcm configurations */ - dma_addr_t gcm_iv_inc1_dma_addr; - /* buffer for internal gcm configurations */ - dma_addr_t gcm_iv_inc2_dma_addr; - dma_addr_t hkey_dma_addr; /* Phys. address of hkey */ - dma_addr_t gcm_block_len_dma_addr; /* Phys. address of gcm block len */ - bool is_gcm4543; - - u8 *icv_virt_addr; /* Virt. address of ICV */ - struct async_gen_req_ctx gen_ctx; - struct cc_mlli assoc; - struct cc_mlli src; - struct cc_mlli dst; - struct scatterlist *src_sgl; - struct scatterlist *dst_sgl; - unsigned int src_offset; - unsigned int dst_offset; - enum cc_req_dma_buf_type assoc_buff_type; - enum cc_req_dma_buf_type data_buff_type; - struct mlli_params mlli_params; - unsigned int cryptlen; - struct scatterlist ccm_adata_sg; - enum aead_ccm_header_size ccm_hdr_size; - unsigned int req_authsize; - enum drv_cipher_mode cipher_mode; - bool is_icv_fragmented; - bool is_single_pass; - bool plaintext_authenticate_only; //for gcm_rfc4543 -}; - -int cc_aead_alloc(struct cc_drvdata *drvdata); -int cc_aead_free(struct cc_drvdata *drvdata); - -#endif /*__CC_AEAD_H__*/ diff --git a/drivers/staging/ccree/cc_buffer_mgr.c b/drivers/staging/ccree/cc_buffer_mgr.c deleted file mode 100644 index 14b2eabbf70a..000000000000 --- a/drivers/staging/ccree/cc_buffer_mgr.c +++ /dev/null @@ -1,1651 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <crypto/internal/aead.h> -#include <crypto/authenc.h> -#include <crypto/scatterwalk.h> -#include <linux/dmapool.h> -#include <linux/dma-mapping.h> - -#include "cc_buffer_mgr.h" -#include "cc_lli_defs.h" -#include "cc_cipher.h" -#include "cc_hash.h" -#include "cc_aead.h" - -enum dma_buffer_type { - DMA_NULL_TYPE = -1, - DMA_SGL_TYPE = 1, - DMA_BUFF_TYPE = 2, -}; - -struct buff_mgr_handle { - struct dma_pool *mlli_buffs_pool; -}; - -union buffer_array_entry { - struct scatterlist *sgl; - dma_addr_t buffer_dma; -}; - -struct buffer_array { - unsigned int num_of_buffers; - union buffer_array_entry entry[MAX_NUM_OF_BUFFERS_IN_MLLI]; - unsigned int offset[MAX_NUM_OF_BUFFERS_IN_MLLI]; - int nents[MAX_NUM_OF_BUFFERS_IN_MLLI]; - int total_data_len[MAX_NUM_OF_BUFFERS_IN_MLLI]; - enum dma_buffer_type type[MAX_NUM_OF_BUFFERS_IN_MLLI]; - bool is_last[MAX_NUM_OF_BUFFERS_IN_MLLI]; - u32 *mlli_nents[MAX_NUM_OF_BUFFERS_IN_MLLI]; -}; - -static inline char *cc_dma_buf_type(enum cc_req_dma_buf_type type) -{ - switch (type) { - case CC_DMA_BUF_NULL: - return "BUF_NULL"; - case CC_DMA_BUF_DLLI: - return "BUF_DLLI"; - case CC_DMA_BUF_MLLI: - return "BUF_MLLI"; - default: - return "BUF_INVALID"; - } -} - -/** - * cc_copy_mac() - Copy MAC to temporary location - * - * @dev: device object - * @req: aead request object - * @dir: [IN] copy from/to sgl - */ -static void cc_copy_mac(struct device *dev, struct aead_request *req, - enum cc_sg_cpy_direct dir) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - u32 skip = req->assoclen + req->cryptlen; - - if (areq_ctx->is_gcm4543) - skip += crypto_aead_ivsize(tfm); - - cc_copy_sg_portion(dev, areq_ctx->backup_mac, req->src, - (skip - areq_ctx->req_authsize), skip, dir); -} - -/** - * cc_get_sgl_nents() - Get scatterlist number of entries. - * - * @sg_list: SG list - * @nbytes: [IN] Total SGL data bytes. - * @lbytes: [OUT] Returns the amount of bytes at the last entry - */ -static unsigned int cc_get_sgl_nents(struct device *dev, - struct scatterlist *sg_list, - unsigned int nbytes, u32 *lbytes, - bool *is_chained) -{ - unsigned int nents = 0; - - while (nbytes && sg_list) { - if (sg_list->length) { - nents++; - /* get the number of bytes in the last entry */ - *lbytes = nbytes; - nbytes -= (sg_list->length > nbytes) ? - nbytes : sg_list->length; - sg_list = sg_next(sg_list); - } else { - sg_list = (struct scatterlist *)sg_page(sg_list); - if (is_chained) - *is_chained = true; - } - } - dev_dbg(dev, "nents %d last bytes %d\n", nents, *lbytes); - return nents; -} - -/** - * cc_zero_sgl() - Zero scatter scatter list data. - * - * @sgl: - */ -void cc_zero_sgl(struct scatterlist *sgl, u32 data_len) -{ - struct scatterlist *current_sg = sgl; - int sg_index = 0; - - while (sg_index <= data_len) { - if (!current_sg) { - /* reached the end of the sgl --> just return back */ - return; - } - memset(sg_virt(current_sg), 0, current_sg->length); - sg_index += current_sg->length; - current_sg = sg_next(current_sg); - } -} - -/** - * cc_copy_sg_portion() - Copy scatter list data, - * from to_skip to end, to dest and vice versa - * - * @dest: - * @sg: - * @to_skip: - * @end: - * @direct: - */ -void cc_copy_sg_portion(struct device *dev, u8 *dest, struct scatterlist *sg, - u32 to_skip, u32 end, enum cc_sg_cpy_direct direct) -{ - u32 nents, lbytes; - - nents = cc_get_sgl_nents(dev, sg, end, &lbytes, NULL); - sg_copy_buffer(sg, nents, (void *)dest, (end - to_skip + 1), to_skip, - (direct == CC_SG_TO_BUF)); -} - -static int cc_render_buff_to_mlli(struct device *dev, dma_addr_t buff_dma, - u32 buff_size, u32 *curr_nents, - u32 **mlli_entry_pp) -{ - u32 *mlli_entry_p = *mlli_entry_pp; - u32 new_nents; - - /* Verify there is no memory overflow*/ - new_nents = (*curr_nents + buff_size / CC_MAX_MLLI_ENTRY_SIZE + 1); - if (new_nents > MAX_NUM_OF_TOTAL_MLLI_ENTRIES) - return -ENOMEM; - - /*handle buffer longer than 64 kbytes */ - while (buff_size > CC_MAX_MLLI_ENTRY_SIZE) { - cc_lli_set_addr(mlli_entry_p, buff_dma); - cc_lli_set_size(mlli_entry_p, CC_MAX_MLLI_ENTRY_SIZE); - dev_dbg(dev, "entry[%d]: single_buff=0x%08X size=%08X\n", - *curr_nents, mlli_entry_p[LLI_WORD0_OFFSET], - mlli_entry_p[LLI_WORD1_OFFSET]); - buff_dma += CC_MAX_MLLI_ENTRY_SIZE; - buff_size -= CC_MAX_MLLI_ENTRY_SIZE; - mlli_entry_p = mlli_entry_p + 2; - (*curr_nents)++; - } - /*Last entry */ - cc_lli_set_addr(mlli_entry_p, buff_dma); - cc_lli_set_size(mlli_entry_p, buff_size); - dev_dbg(dev, "entry[%d]: single_buff=0x%08X size=%08X\n", - *curr_nents, mlli_entry_p[LLI_WORD0_OFFSET], - mlli_entry_p[LLI_WORD1_OFFSET]); - mlli_entry_p = mlli_entry_p + 2; - *mlli_entry_pp = mlli_entry_p; - (*curr_nents)++; - return 0; -} - -static int cc_render_sg_to_mlli(struct device *dev, struct scatterlist *sgl, - u32 sgl_data_len, u32 sgl_offset, - u32 *curr_nents, u32 **mlli_entry_pp) -{ - struct scatterlist *curr_sgl = sgl; - u32 *mlli_entry_p = *mlli_entry_pp; - s32 rc = 0; - - for ( ; (curr_sgl && sgl_data_len); - curr_sgl = sg_next(curr_sgl)) { - u32 entry_data_len = - (sgl_data_len > sg_dma_len(curr_sgl) - sgl_offset) ? - sg_dma_len(curr_sgl) - sgl_offset : - sgl_data_len; - sgl_data_len -= entry_data_len; - rc = cc_render_buff_to_mlli(dev, sg_dma_address(curr_sgl) + - sgl_offset, entry_data_len, - curr_nents, &mlli_entry_p); - if (rc) - return rc; - - sgl_offset = 0; - } - *mlli_entry_pp = mlli_entry_p; - return 0; -} - -static int cc_generate_mlli(struct device *dev, struct buffer_array *sg_data, - struct mlli_params *mlli_params, gfp_t flags) -{ - u32 *mlli_p; - u32 total_nents = 0, prev_total_nents = 0; - int rc = 0, i; - - dev_dbg(dev, "NUM of SG's = %d\n", sg_data->num_of_buffers); - - /* Allocate memory from the pointed pool */ - mlli_params->mlli_virt_addr = - dma_pool_alloc(mlli_params->curr_pool, flags, - &mlli_params->mlli_dma_addr); - if (!mlli_params->mlli_virt_addr) { - dev_err(dev, "dma_pool_alloc() failed\n"); - rc = -ENOMEM; - goto build_mlli_exit; - } - /* Point to start of MLLI */ - mlli_p = (u32 *)mlli_params->mlli_virt_addr; - /* go over all SG's and link it to one MLLI table */ - for (i = 0; i < sg_data->num_of_buffers; i++) { - union buffer_array_entry *entry = &sg_data->entry[i]; - u32 tot_len = sg_data->total_data_len[i]; - u32 offset = sg_data->offset[i]; - - if (sg_data->type[i] == DMA_SGL_TYPE) - rc = cc_render_sg_to_mlli(dev, entry->sgl, tot_len, - offset, &total_nents, - &mlli_p); - else /*DMA_BUFF_TYPE*/ - rc = cc_render_buff_to_mlli(dev, entry->buffer_dma, - tot_len, &total_nents, - &mlli_p); - if (rc) - return rc; - - /* set last bit in the current table */ - if (sg_data->mlli_nents[i]) { - /*Calculate the current MLLI table length for the - *length field in the descriptor - */ - *sg_data->mlli_nents[i] += - (total_nents - prev_total_nents); - prev_total_nents = total_nents; - } - } - - /* Set MLLI size for the bypass operation */ - mlli_params->mlli_len = (total_nents * LLI_ENTRY_BYTE_SIZE); - - dev_dbg(dev, "MLLI params: virt_addr=%pK dma_addr=%pad mlli_len=0x%X\n", - mlli_params->mlli_virt_addr, &mlli_params->mlli_dma_addr, - mlli_params->mlli_len); - -build_mlli_exit: - return rc; -} - -static void cc_add_buffer_entry(struct device *dev, - struct buffer_array *sgl_data, - dma_addr_t buffer_dma, unsigned int buffer_len, - bool is_last_entry, u32 *mlli_nents) -{ - unsigned int index = sgl_data->num_of_buffers; - - dev_dbg(dev, "index=%u single_buff=%pad buffer_len=0x%08X is_last=%d\n", - index, &buffer_dma, buffer_len, is_last_entry); - sgl_data->nents[index] = 1; - sgl_data->entry[index].buffer_dma = buffer_dma; - sgl_data->offset[index] = 0; - sgl_data->total_data_len[index] = buffer_len; - sgl_data->type[index] = DMA_BUFF_TYPE; - sgl_data->is_last[index] = is_last_entry; - sgl_data->mlli_nents[index] = mlli_nents; - if (sgl_data->mlli_nents[index]) - *sgl_data->mlli_nents[index] = 0; - sgl_data->num_of_buffers++; -} - -static void cc_add_sg_entry(struct device *dev, struct buffer_array *sgl_data, - unsigned int nents, struct scatterlist *sgl, - unsigned int data_len, unsigned int data_offset, - bool is_last_table, u32 *mlli_nents) -{ - unsigned int index = sgl_data->num_of_buffers; - - dev_dbg(dev, "index=%u nents=%u sgl=%pK data_len=0x%08X is_last=%d\n", - index, nents, sgl, data_len, is_last_table); - sgl_data->nents[index] = nents; - sgl_data->entry[index].sgl = sgl; - sgl_data->offset[index] = data_offset; - sgl_data->total_data_len[index] = data_len; - sgl_data->type[index] = DMA_SGL_TYPE; - sgl_data->is_last[index] = is_last_table; - sgl_data->mlli_nents[index] = mlli_nents; - if (sgl_data->mlli_nents[index]) - *sgl_data->mlli_nents[index] = 0; - sgl_data->num_of_buffers++; -} - -static int cc_dma_map_sg(struct device *dev, struct scatterlist *sg, u32 nents, - enum dma_data_direction direction) -{ - u32 i, j; - struct scatterlist *l_sg = sg; - - for (i = 0; i < nents; i++) { - if (!l_sg) - break; - if (dma_map_sg(dev, l_sg, 1, direction) != 1) { - dev_err(dev, "dma_map_page() sg buffer failed\n"); - goto err; - } - l_sg = sg_next(l_sg); - } - return nents; - -err: - /* Restore mapped parts */ - for (j = 0; j < i; j++) { - if (!sg) - break; - dma_unmap_sg(dev, sg, 1, direction); - sg = sg_next(sg); - } - return 0; -} - -static int cc_map_sg(struct device *dev, struct scatterlist *sg, - unsigned int nbytes, int direction, u32 *nents, - u32 max_sg_nents, u32 *lbytes, u32 *mapped_nents) -{ - bool is_chained = false; - - if (sg_is_last(sg)) { - /* One entry only case -set to DLLI */ - if (dma_map_sg(dev, sg, 1, direction) != 1) { - dev_err(dev, "dma_map_sg() single buffer failed\n"); - return -ENOMEM; - } - dev_dbg(dev, "Mapped sg: dma_address=%pad page=%p addr=%pK offset=%u length=%u\n", - &sg_dma_address(sg), sg_page(sg), sg_virt(sg), - sg->offset, sg->length); - *lbytes = nbytes; - *nents = 1; - *mapped_nents = 1; - } else { /*sg_is_last*/ - *nents = cc_get_sgl_nents(dev, sg, nbytes, lbytes, - &is_chained); - if (*nents > max_sg_nents) { - *nents = 0; - dev_err(dev, "Too many fragments. current %d max %d\n", - *nents, max_sg_nents); - return -ENOMEM; - } - if (!is_chained) { - /* In case of mmu the number of mapped nents might - * be changed from the original sgl nents - */ - *mapped_nents = dma_map_sg(dev, sg, *nents, direction); - if (*mapped_nents == 0) { - *nents = 0; - dev_err(dev, "dma_map_sg() sg buffer failed\n"); - return -ENOMEM; - } - } else { - /*In this case the driver maps entry by entry so it - * must have the same nents before and after map - */ - *mapped_nents = cc_dma_map_sg(dev, sg, *nents, - direction); - if (*mapped_nents != *nents) { - *nents = *mapped_nents; - dev_err(dev, "dma_map_sg() sg buffer failed\n"); - return -ENOMEM; - } - } - } - - return 0; -} - -static int -cc_set_aead_conf_buf(struct device *dev, struct aead_req_ctx *areq_ctx, - u8 *config_data, struct buffer_array *sg_data, - unsigned int assoclen) -{ - dev_dbg(dev, " handle additional data config set to DLLI\n"); - /* create sg for the current buffer */ - sg_init_one(&areq_ctx->ccm_adata_sg, config_data, - AES_BLOCK_SIZE + areq_ctx->ccm_hdr_size); - if (dma_map_sg(dev, &areq_ctx->ccm_adata_sg, 1, DMA_TO_DEVICE) != 1) { - dev_err(dev, "dma_map_sg() config buffer failed\n"); - return -ENOMEM; - } - dev_dbg(dev, "Mapped curr_buff: dma_address=%pad page=%p addr=%pK offset=%u length=%u\n", - &sg_dma_address(&areq_ctx->ccm_adata_sg), - sg_page(&areq_ctx->ccm_adata_sg), - sg_virt(&areq_ctx->ccm_adata_sg), - areq_ctx->ccm_adata_sg.offset, areq_ctx->ccm_adata_sg.length); - /* prepare for case of MLLI */ - if (assoclen > 0) { - cc_add_sg_entry(dev, sg_data, 1, &areq_ctx->ccm_adata_sg, - (AES_BLOCK_SIZE + areq_ctx->ccm_hdr_size), - 0, false, NULL); - } - return 0; -} - -static int cc_set_hash_buf(struct device *dev, struct ahash_req_ctx *areq_ctx, - u8 *curr_buff, u32 curr_buff_cnt, - struct buffer_array *sg_data) -{ - dev_dbg(dev, " handle curr buff %x set to DLLI\n", curr_buff_cnt); - /* create sg for the current buffer */ - sg_init_one(areq_ctx->buff_sg, curr_buff, curr_buff_cnt); - if (dma_map_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE) != 1) { - dev_err(dev, "dma_map_sg() src buffer failed\n"); - return -ENOMEM; - } - dev_dbg(dev, "Mapped curr_buff: dma_address=%pad page=%p addr=%pK offset=%u length=%u\n", - &sg_dma_address(areq_ctx->buff_sg), sg_page(areq_ctx->buff_sg), - sg_virt(areq_ctx->buff_sg), areq_ctx->buff_sg->offset, - areq_ctx->buff_sg->length); - areq_ctx->data_dma_buf_type = CC_DMA_BUF_DLLI; - areq_ctx->curr_sg = areq_ctx->buff_sg; - areq_ctx->in_nents = 0; - /* prepare for case of MLLI */ - cc_add_sg_entry(dev, sg_data, 1, areq_ctx->buff_sg, curr_buff_cnt, 0, - false, NULL); - return 0; -} - -void cc_unmap_blkcipher_request(struct device *dev, void *ctx, - unsigned int ivsize, struct scatterlist *src, - struct scatterlist *dst) -{ - struct blkcipher_req_ctx *req_ctx = (struct blkcipher_req_ctx *)ctx; - - if (req_ctx->gen_ctx.iv_dma_addr) { - dev_dbg(dev, "Unmapped iv: iv_dma_addr=%pad iv_size=%u\n", - &req_ctx->gen_ctx.iv_dma_addr, ivsize); - dma_unmap_single(dev, req_ctx->gen_ctx.iv_dma_addr, - ivsize, - req_ctx->is_giv ? DMA_BIDIRECTIONAL : - DMA_TO_DEVICE); - } - /* Release pool */ - if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI && - req_ctx->mlli_params.mlli_virt_addr) { - dma_pool_free(req_ctx->mlli_params.curr_pool, - req_ctx->mlli_params.mlli_virt_addr, - req_ctx->mlli_params.mlli_dma_addr); - } - - dma_unmap_sg(dev, src, req_ctx->in_nents, DMA_BIDIRECTIONAL); - dev_dbg(dev, "Unmapped req->src=%pK\n", sg_virt(src)); - - if (src != dst) { - dma_unmap_sg(dev, dst, req_ctx->out_nents, DMA_BIDIRECTIONAL); - dev_dbg(dev, "Unmapped req->dst=%pK\n", sg_virt(dst)); - } -} - -int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx, - unsigned int ivsize, unsigned int nbytes, - void *info, struct scatterlist *src, - struct scatterlist *dst, gfp_t flags) -{ - struct blkcipher_req_ctx *req_ctx = (struct blkcipher_req_ctx *)ctx; - struct mlli_params *mlli_params = &req_ctx->mlli_params; - struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle; - struct device *dev = drvdata_to_dev(drvdata); - struct buffer_array sg_data; - u32 dummy = 0; - int rc = 0; - u32 mapped_nents = 0; - - req_ctx->dma_buf_type = CC_DMA_BUF_DLLI; - mlli_params->curr_pool = NULL; - sg_data.num_of_buffers = 0; - - /* Map IV buffer */ - if (ivsize) { - dump_byte_array("iv", (u8 *)info, ivsize); - req_ctx->gen_ctx.iv_dma_addr = - dma_map_single(dev, (void *)info, - ivsize, - req_ctx->is_giv ? DMA_BIDIRECTIONAL : - DMA_TO_DEVICE); - if (dma_mapping_error(dev, req_ctx->gen_ctx.iv_dma_addr)) { - dev_err(dev, "Mapping iv %u B at va=%pK for DMA failed\n", - ivsize, info); - return -ENOMEM; - } - dev_dbg(dev, "Mapped iv %u B at va=%pK to dma=%pad\n", - ivsize, info, &req_ctx->gen_ctx.iv_dma_addr); - } else { - req_ctx->gen_ctx.iv_dma_addr = 0; - } - - /* Map the src SGL */ - rc = cc_map_sg(dev, src, nbytes, DMA_BIDIRECTIONAL, &req_ctx->in_nents, - LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, &mapped_nents); - if (rc) { - rc = -ENOMEM; - goto ablkcipher_exit; - } - if (mapped_nents > 1) - req_ctx->dma_buf_type = CC_DMA_BUF_MLLI; - - if (src == dst) { - /* Handle inplace operation */ - if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI) { - req_ctx->out_nents = 0; - cc_add_sg_entry(dev, &sg_data, req_ctx->in_nents, src, - nbytes, 0, true, - &req_ctx->in_mlli_nents); - } - } else { - /* Map the dst sg */ - if (cc_map_sg(dev, dst, nbytes, DMA_BIDIRECTIONAL, - &req_ctx->out_nents, LLI_MAX_NUM_OF_DATA_ENTRIES, - &dummy, &mapped_nents)) { - rc = -ENOMEM; - goto ablkcipher_exit; - } - if (mapped_nents > 1) - req_ctx->dma_buf_type = CC_DMA_BUF_MLLI; - - if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI) { - cc_add_sg_entry(dev, &sg_data, req_ctx->in_nents, src, - nbytes, 0, true, - &req_ctx->in_mlli_nents); - cc_add_sg_entry(dev, &sg_data, req_ctx->out_nents, dst, - nbytes, 0, true, - &req_ctx->out_mlli_nents); - } - } - - if (req_ctx->dma_buf_type == CC_DMA_BUF_MLLI) { - mlli_params->curr_pool = buff_mgr->mlli_buffs_pool; - rc = cc_generate_mlli(dev, &sg_data, mlli_params, flags); - if (rc) - goto ablkcipher_exit; - } - - dev_dbg(dev, "areq_ctx->dma_buf_type = %s\n", - cc_dma_buf_type(req_ctx->dma_buf_type)); - - return 0; - -ablkcipher_exit: - cc_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst); - return rc; -} - -void cc_unmap_aead_request(struct device *dev, struct aead_request *req) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - unsigned int hw_iv_size = areq_ctx->hw_iv_size; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - struct cc_drvdata *drvdata = dev_get_drvdata(dev); - u32 dummy; - bool chained; - u32 size_to_unmap = 0; - - if (areq_ctx->mac_buf_dma_addr) { - dma_unmap_single(dev, areq_ctx->mac_buf_dma_addr, - MAX_MAC_SIZE, DMA_BIDIRECTIONAL); - } - - if (areq_ctx->cipher_mode == DRV_CIPHER_GCTR) { - if (areq_ctx->hkey_dma_addr) { - dma_unmap_single(dev, areq_ctx->hkey_dma_addr, - AES_BLOCK_SIZE, DMA_BIDIRECTIONAL); - } - - if (areq_ctx->gcm_block_len_dma_addr) { - dma_unmap_single(dev, areq_ctx->gcm_block_len_dma_addr, - AES_BLOCK_SIZE, DMA_TO_DEVICE); - } - - if (areq_ctx->gcm_iv_inc1_dma_addr) { - dma_unmap_single(dev, areq_ctx->gcm_iv_inc1_dma_addr, - AES_BLOCK_SIZE, DMA_TO_DEVICE); - } - - if (areq_ctx->gcm_iv_inc2_dma_addr) { - dma_unmap_single(dev, areq_ctx->gcm_iv_inc2_dma_addr, - AES_BLOCK_SIZE, DMA_TO_DEVICE); - } - } - - if (areq_ctx->ccm_hdr_size != ccm_header_size_null) { - if (areq_ctx->ccm_iv0_dma_addr) { - dma_unmap_single(dev, areq_ctx->ccm_iv0_dma_addr, - AES_BLOCK_SIZE, DMA_TO_DEVICE); - } - - dma_unmap_sg(dev, &areq_ctx->ccm_adata_sg, 1, DMA_TO_DEVICE); - } - if (areq_ctx->gen_ctx.iv_dma_addr) { - dma_unmap_single(dev, areq_ctx->gen_ctx.iv_dma_addr, - hw_iv_size, DMA_BIDIRECTIONAL); - } - - /*In case a pool was set, a table was - *allocated and should be released - */ - if (areq_ctx->mlli_params.curr_pool) { - dev_dbg(dev, "free MLLI buffer: dma=%pad virt=%pK\n", - &areq_ctx->mlli_params.mlli_dma_addr, - areq_ctx->mlli_params.mlli_virt_addr); - dma_pool_free(areq_ctx->mlli_params.curr_pool, - areq_ctx->mlli_params.mlli_virt_addr, - areq_ctx->mlli_params.mlli_dma_addr); - } - - dev_dbg(dev, "Unmapping src sgl: req->src=%pK areq_ctx->src.nents=%u areq_ctx->assoc.nents=%u assoclen:%u cryptlen=%u\n", - sg_virt(req->src), areq_ctx->src.nents, areq_ctx->assoc.nents, - req->assoclen, req->cryptlen); - size_to_unmap = req->assoclen + req->cryptlen; - if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT) - size_to_unmap += areq_ctx->req_authsize; - if (areq_ctx->is_gcm4543) - size_to_unmap += crypto_aead_ivsize(tfm); - - dma_unmap_sg(dev, req->src, - cc_get_sgl_nents(dev, req->src, size_to_unmap, - &dummy, &chained), - DMA_BIDIRECTIONAL); - if (req->src != req->dst) { - dev_dbg(dev, "Unmapping dst sgl: req->dst=%pK\n", - sg_virt(req->dst)); - dma_unmap_sg(dev, req->dst, - cc_get_sgl_nents(dev, req->dst, size_to_unmap, - &dummy, &chained), - DMA_BIDIRECTIONAL); - } - if (drvdata->coherent && - areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT && - req->src == req->dst) { - /* copy back mac from temporary location to deal with possible - * data memory overriding that caused by cache coherence - * problem. - */ - cc_copy_mac(dev, req, CC_SG_FROM_BUF); - } -} - -static int cc_get_aead_icv_nents(struct device *dev, struct scatterlist *sgl, - unsigned int sgl_nents, unsigned int authsize, - u32 last_entry_data_size, - bool *is_icv_fragmented) -{ - unsigned int icv_max_size = 0; - unsigned int icv_required_size = authsize > last_entry_data_size ? - (authsize - last_entry_data_size) : - authsize; - unsigned int nents; - unsigned int i; - - if (sgl_nents < MAX_ICV_NENTS_SUPPORTED) { - *is_icv_fragmented = false; - return 0; - } - - for (i = 0 ; i < (sgl_nents - MAX_ICV_NENTS_SUPPORTED) ; i++) { - if (!sgl) - break; - sgl = sg_next(sgl); - } - - if (sgl) - icv_max_size = sgl->length; - - if (last_entry_data_size > authsize) { - /* ICV attached to data in last entry (not fragmented!) */ - nents = 0; - *is_icv_fragmented = false; - } else if (last_entry_data_size == authsize) { - /* ICV placed in whole last entry (not fragmented!) */ - nents = 1; - *is_icv_fragmented = false; - } else if (icv_max_size > icv_required_size) { - nents = 1; - *is_icv_fragmented = true; - } else if (icv_max_size == icv_required_size) { - nents = 2; - *is_icv_fragmented = true; - } else { - dev_err(dev, "Unsupported num. of ICV fragments (> %d)\n", - MAX_ICV_NENTS_SUPPORTED); - nents = -1; /*unsupported*/ - } - dev_dbg(dev, "is_frag=%s icv_nents=%u\n", - (*is_icv_fragmented ? "true" : "false"), nents); - - return nents; -} - -static int cc_aead_chain_iv(struct cc_drvdata *drvdata, - struct aead_request *req, - struct buffer_array *sg_data, - bool is_last, bool do_chain) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - unsigned int hw_iv_size = areq_ctx->hw_iv_size; - struct device *dev = drvdata_to_dev(drvdata); - int rc = 0; - - if (!req->iv) { - areq_ctx->gen_ctx.iv_dma_addr = 0; - goto chain_iv_exit; - } - - areq_ctx->gen_ctx.iv_dma_addr = dma_map_single(dev, req->iv, - hw_iv_size, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, areq_ctx->gen_ctx.iv_dma_addr)) { - dev_err(dev, "Mapping iv %u B at va=%pK for DMA failed\n", - hw_iv_size, req->iv); - rc = -ENOMEM; - goto chain_iv_exit; - } - - dev_dbg(dev, "Mapped iv %u B at va=%pK to dma=%pad\n", - hw_iv_size, req->iv, &areq_ctx->gen_ctx.iv_dma_addr); - // TODO: what about CTR?? ask Ron - if (do_chain && areq_ctx->plaintext_authenticate_only) { - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - unsigned int iv_size_to_authenc = crypto_aead_ivsize(tfm); - unsigned int iv_ofs = GCM_BLOCK_RFC4_IV_OFFSET; - /* Chain to given list */ - cc_add_buffer_entry(dev, sg_data, - (areq_ctx->gen_ctx.iv_dma_addr + iv_ofs), - iv_size_to_authenc, is_last, - &areq_ctx->assoc.mlli_nents); - areq_ctx->assoc_buff_type = CC_DMA_BUF_MLLI; - } - -chain_iv_exit: - return rc; -} - -static int cc_aead_chain_assoc(struct cc_drvdata *drvdata, - struct aead_request *req, - struct buffer_array *sg_data, - bool is_last, bool do_chain) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - int rc = 0; - u32 mapped_nents = 0; - struct scatterlist *current_sg = req->src; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - unsigned int sg_index = 0; - u32 size_of_assoc = req->assoclen; - struct device *dev = drvdata_to_dev(drvdata); - - if (areq_ctx->is_gcm4543) - size_of_assoc += crypto_aead_ivsize(tfm); - - if (!sg_data) { - rc = -EINVAL; - goto chain_assoc_exit; - } - - if (req->assoclen == 0) { - areq_ctx->assoc_buff_type = CC_DMA_BUF_NULL; - areq_ctx->assoc.nents = 0; - areq_ctx->assoc.mlli_nents = 0; - dev_dbg(dev, "Chain assoc of length 0: buff_type=%s nents=%u\n", - cc_dma_buf_type(areq_ctx->assoc_buff_type), - areq_ctx->assoc.nents); - goto chain_assoc_exit; - } - - //iterate over the sgl to see how many entries are for associated data - //it is assumed that if we reach here , the sgl is already mapped - sg_index = current_sg->length; - //the first entry in the scatter list contains all the associated data - if (sg_index > size_of_assoc) { - mapped_nents++; - } else { - while (sg_index <= size_of_assoc) { - current_sg = sg_next(current_sg); - /* if have reached the end of the sgl, then this is - * unexpected - */ - if (!current_sg) { - dev_err(dev, "reached end of sg list. unexpected\n"); - return -EINVAL; - } - sg_index += current_sg->length; - mapped_nents++; - } - } - if (mapped_nents > LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES) { - dev_err(dev, "Too many fragments. current %d max %d\n", - mapped_nents, LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES); - return -ENOMEM; - } - areq_ctx->assoc.nents = mapped_nents; - - /* in CCM case we have additional entry for - * ccm header configurations - */ - if (areq_ctx->ccm_hdr_size != ccm_header_size_null) { - if ((mapped_nents + 1) > LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES) { - dev_err(dev, "CCM case.Too many fragments. Current %d max %d\n", - (areq_ctx->assoc.nents + 1), - LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES); - rc = -ENOMEM; - goto chain_assoc_exit; - } - } - - if (mapped_nents == 1 && areq_ctx->ccm_hdr_size == ccm_header_size_null) - areq_ctx->assoc_buff_type = CC_DMA_BUF_DLLI; - else - areq_ctx->assoc_buff_type = CC_DMA_BUF_MLLI; - - if (do_chain || areq_ctx->assoc_buff_type == CC_DMA_BUF_MLLI) { - dev_dbg(dev, "Chain assoc: buff_type=%s nents=%u\n", - cc_dma_buf_type(areq_ctx->assoc_buff_type), - areq_ctx->assoc.nents); - cc_add_sg_entry(dev, sg_data, areq_ctx->assoc.nents, req->src, - req->assoclen, 0, is_last, - &areq_ctx->assoc.mlli_nents); - areq_ctx->assoc_buff_type = CC_DMA_BUF_MLLI; - } - -chain_assoc_exit: - return rc; -} - -static void cc_prepare_aead_data_dlli(struct aead_request *req, - u32 *src_last_bytes, u32 *dst_last_bytes) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type; - unsigned int authsize = areq_ctx->req_authsize; - - areq_ctx->is_icv_fragmented = false; - if (req->src == req->dst) { - /*INPLACE*/ - areq_ctx->icv_dma_addr = sg_dma_address(areq_ctx->src_sgl) + - (*src_last_bytes - authsize); - areq_ctx->icv_virt_addr = sg_virt(areq_ctx->src_sgl) + - (*src_last_bytes - authsize); - } else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) { - /*NON-INPLACE and DECRYPT*/ - areq_ctx->icv_dma_addr = sg_dma_address(areq_ctx->src_sgl) + - (*src_last_bytes - authsize); - areq_ctx->icv_virt_addr = sg_virt(areq_ctx->src_sgl) + - (*src_last_bytes - authsize); - } else { - /*NON-INPLACE and ENCRYPT*/ - areq_ctx->icv_dma_addr = sg_dma_address(areq_ctx->dst_sgl) + - (*dst_last_bytes - authsize); - areq_ctx->icv_virt_addr = sg_virt(areq_ctx->dst_sgl) + - (*dst_last_bytes - authsize); - } -} - -static int cc_prepare_aead_data_mlli(struct cc_drvdata *drvdata, - struct aead_request *req, - struct buffer_array *sg_data, - u32 *src_last_bytes, u32 *dst_last_bytes, - bool is_last_table) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type; - unsigned int authsize = areq_ctx->req_authsize; - int rc = 0, icv_nents; - struct device *dev = drvdata_to_dev(drvdata); - struct scatterlist *sg; - - if (req->src == req->dst) { - /*INPLACE*/ - cc_add_sg_entry(dev, sg_data, areq_ctx->src.nents, - areq_ctx->src_sgl, areq_ctx->cryptlen, - areq_ctx->src_offset, is_last_table, - &areq_ctx->src.mlli_nents); - - icv_nents = cc_get_aead_icv_nents(dev, areq_ctx->src_sgl, - areq_ctx->src.nents, - authsize, *src_last_bytes, - &areq_ctx->is_icv_fragmented); - if (icv_nents < 0) { - rc = -ENOTSUPP; - goto prepare_data_mlli_exit; - } - - if (areq_ctx->is_icv_fragmented) { - /* Backup happens only when ICV is fragmented, ICV - * verification is made by CPU compare in order to - * simplify MAC verification upon request completion - */ - if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) { - /* In coherent platforms (e.g. ACP) - * already copying ICV for any - * INPLACE-DECRYPT operation, hence - * we must neglect this code. - */ - if (!drvdata->coherent) - cc_copy_mac(dev, req, CC_SG_TO_BUF); - - areq_ctx->icv_virt_addr = areq_ctx->backup_mac; - } else { - areq_ctx->icv_virt_addr = areq_ctx->mac_buf; - areq_ctx->icv_dma_addr = - areq_ctx->mac_buf_dma_addr; - } - } else { /* Contig. ICV */ - sg = &areq_ctx->src_sgl[areq_ctx->src.nents - 1]; - /*Should hanlde if the sg is not contig.*/ - areq_ctx->icv_dma_addr = sg_dma_address(sg) + - (*src_last_bytes - authsize); - areq_ctx->icv_virt_addr = sg_virt(sg) + - (*src_last_bytes - authsize); - } - - } else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) { - /*NON-INPLACE and DECRYPT*/ - cc_add_sg_entry(dev, sg_data, areq_ctx->src.nents, - areq_ctx->src_sgl, areq_ctx->cryptlen, - areq_ctx->src_offset, is_last_table, - &areq_ctx->src.mlli_nents); - cc_add_sg_entry(dev, sg_data, areq_ctx->dst.nents, - areq_ctx->dst_sgl, areq_ctx->cryptlen, - areq_ctx->dst_offset, is_last_table, - &areq_ctx->dst.mlli_nents); - - icv_nents = cc_get_aead_icv_nents(dev, areq_ctx->src_sgl, - areq_ctx->src.nents, - authsize, *src_last_bytes, - &areq_ctx->is_icv_fragmented); - if (icv_nents < 0) { - rc = -ENOTSUPP; - goto prepare_data_mlli_exit; - } - - /* Backup happens only when ICV is fragmented, ICV - * verification is made by CPU compare in order to simplify - * MAC verification upon request completion - */ - if (areq_ctx->is_icv_fragmented) { - cc_copy_mac(dev, req, CC_SG_TO_BUF); - areq_ctx->icv_virt_addr = areq_ctx->backup_mac; - - } else { /* Contig. ICV */ - sg = &areq_ctx->src_sgl[areq_ctx->src.nents - 1]; - /*Should hanlde if the sg is not contig.*/ - areq_ctx->icv_dma_addr = sg_dma_address(sg) + - (*src_last_bytes - authsize); - areq_ctx->icv_virt_addr = sg_virt(sg) + - (*src_last_bytes - authsize); - } - - } else { - /*NON-INPLACE and ENCRYPT*/ - cc_add_sg_entry(dev, sg_data, areq_ctx->dst.nents, - areq_ctx->dst_sgl, areq_ctx->cryptlen, - areq_ctx->dst_offset, is_last_table, - &areq_ctx->dst.mlli_nents); - cc_add_sg_entry(dev, sg_data, areq_ctx->src.nents, - areq_ctx->src_sgl, areq_ctx->cryptlen, - areq_ctx->src_offset, is_last_table, - &areq_ctx->src.mlli_nents); - - icv_nents = cc_get_aead_icv_nents(dev, areq_ctx->dst_sgl, - areq_ctx->dst.nents, - authsize, *dst_last_bytes, - &areq_ctx->is_icv_fragmented); - if (icv_nents < 0) { - rc = -ENOTSUPP; - goto prepare_data_mlli_exit; - } - - if (!areq_ctx->is_icv_fragmented) { - sg = &areq_ctx->dst_sgl[areq_ctx->dst.nents - 1]; - /* Contig. ICV */ - areq_ctx->icv_dma_addr = sg_dma_address(sg) + - (*dst_last_bytes - authsize); - areq_ctx->icv_virt_addr = sg_virt(sg) + - (*dst_last_bytes - authsize); - } else { - areq_ctx->icv_dma_addr = areq_ctx->mac_buf_dma_addr; - areq_ctx->icv_virt_addr = areq_ctx->mac_buf; - } - } - -prepare_data_mlli_exit: - return rc; -} - -static int cc_aead_chain_data(struct cc_drvdata *drvdata, - struct aead_request *req, - struct buffer_array *sg_data, - bool is_last_table, bool do_chain) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - struct device *dev = drvdata_to_dev(drvdata); - enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type; - unsigned int authsize = areq_ctx->req_authsize; - int src_last_bytes = 0, dst_last_bytes = 0; - int rc = 0; - u32 src_mapped_nents = 0, dst_mapped_nents = 0; - u32 offset = 0; - /* non-inplace mode */ - unsigned int size_for_map = req->assoclen + req->cryptlen; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - u32 sg_index = 0; - bool chained = false; - bool is_gcm4543 = areq_ctx->is_gcm4543; - u32 size_to_skip = req->assoclen; - - if (is_gcm4543) - size_to_skip += crypto_aead_ivsize(tfm); - - offset = size_to_skip; - - if (!sg_data) - return -EINVAL; - - areq_ctx->src_sgl = req->src; - areq_ctx->dst_sgl = req->dst; - - if (is_gcm4543) - size_for_map += crypto_aead_ivsize(tfm); - - size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? - authsize : 0; - src_mapped_nents = cc_get_sgl_nents(dev, req->src, size_for_map, - &src_last_bytes, &chained); - sg_index = areq_ctx->src_sgl->length; - //check where the data starts - while (sg_index <= size_to_skip) { - offset -= areq_ctx->src_sgl->length; - areq_ctx->src_sgl = sg_next(areq_ctx->src_sgl); - //if have reached the end of the sgl, then this is unexpected - if (!areq_ctx->src_sgl) { - dev_err(dev, "reached end of sg list. unexpected\n"); - return -EINVAL; - } - sg_index += areq_ctx->src_sgl->length; - src_mapped_nents--; - } - if (src_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES) { - dev_err(dev, "Too many fragments. current %d max %d\n", - src_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES); - return -ENOMEM; - } - - areq_ctx->src.nents = src_mapped_nents; - - areq_ctx->src_offset = offset; - - if (req->src != req->dst) { - size_for_map = req->assoclen + req->cryptlen; - size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? - authsize : 0; - if (is_gcm4543) - size_for_map += crypto_aead_ivsize(tfm); - - rc = cc_map_sg(dev, req->dst, size_for_map, DMA_BIDIRECTIONAL, - &areq_ctx->dst.nents, - LLI_MAX_NUM_OF_DATA_ENTRIES, &dst_last_bytes, - &dst_mapped_nents); - if (rc) { - rc = -ENOMEM; - goto chain_data_exit; - } - } - - dst_mapped_nents = cc_get_sgl_nents(dev, req->dst, size_for_map, - &dst_last_bytes, &chained); - sg_index = areq_ctx->dst_sgl->length; - offset = size_to_skip; - - //check where the data starts - while (sg_index <= size_to_skip) { - offset -= areq_ctx->dst_sgl->length; - areq_ctx->dst_sgl = sg_next(areq_ctx->dst_sgl); - //if have reached the end of the sgl, then this is unexpected - if (!areq_ctx->dst_sgl) { - dev_err(dev, "reached end of sg list. unexpected\n"); - return -EINVAL; - } - sg_index += areq_ctx->dst_sgl->length; - dst_mapped_nents--; - } - if (dst_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES) { - dev_err(dev, "Too many fragments. current %d max %d\n", - dst_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES); - return -ENOMEM; - } - areq_ctx->dst.nents = dst_mapped_nents; - areq_ctx->dst_offset = offset; - if (src_mapped_nents > 1 || - dst_mapped_nents > 1 || - do_chain) { - areq_ctx->data_buff_type = CC_DMA_BUF_MLLI; - rc = cc_prepare_aead_data_mlli(drvdata, req, sg_data, - &src_last_bytes, - &dst_last_bytes, is_last_table); - } else { - areq_ctx->data_buff_type = CC_DMA_BUF_DLLI; - cc_prepare_aead_data_dlli(req, &src_last_bytes, - &dst_last_bytes); - } - -chain_data_exit: - return rc; -} - -static void cc_update_aead_mlli_nents(struct cc_drvdata *drvdata, - struct aead_request *req) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - u32 curr_mlli_size = 0; - - if (areq_ctx->assoc_buff_type == CC_DMA_BUF_MLLI) { - areq_ctx->assoc.sram_addr = drvdata->mlli_sram_addr; - curr_mlli_size = areq_ctx->assoc.mlli_nents * - LLI_ENTRY_BYTE_SIZE; - } - - if (areq_ctx->data_buff_type == CC_DMA_BUF_MLLI) { - /*Inplace case dst nents equal to src nents*/ - if (req->src == req->dst) { - areq_ctx->dst.mlli_nents = areq_ctx->src.mlli_nents; - areq_ctx->src.sram_addr = drvdata->mlli_sram_addr + - curr_mlli_size; - areq_ctx->dst.sram_addr = areq_ctx->src.sram_addr; - if (!areq_ctx->is_single_pass) - areq_ctx->assoc.mlli_nents += - areq_ctx->src.mlli_nents; - } else { - if (areq_ctx->gen_ctx.op_type == - DRV_CRYPTO_DIRECTION_DECRYPT) { - areq_ctx->src.sram_addr = - drvdata->mlli_sram_addr + - curr_mlli_size; - areq_ctx->dst.sram_addr = - areq_ctx->src.sram_addr + - areq_ctx->src.mlli_nents * - LLI_ENTRY_BYTE_SIZE; - if (!areq_ctx->is_single_pass) - areq_ctx->assoc.mlli_nents += - areq_ctx->src.mlli_nents; - } else { - areq_ctx->dst.sram_addr = - drvdata->mlli_sram_addr + - curr_mlli_size; - areq_ctx->src.sram_addr = - areq_ctx->dst.sram_addr + - areq_ctx->dst.mlli_nents * - LLI_ENTRY_BYTE_SIZE; - if (!areq_ctx->is_single_pass) - areq_ctx->assoc.mlli_nents += - areq_ctx->dst.mlli_nents; - } - } - } -} - -int cc_map_aead_request(struct cc_drvdata *drvdata, struct aead_request *req) -{ - struct aead_req_ctx *areq_ctx = aead_request_ctx(req); - struct mlli_params *mlli_params = &areq_ctx->mlli_params; - struct device *dev = drvdata_to_dev(drvdata); - struct buffer_array sg_data; - unsigned int authsize = areq_ctx->req_authsize; - struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle; - int rc = 0; - struct crypto_aead *tfm = crypto_aead_reqtfm(req); - bool is_gcm4543 = areq_ctx->is_gcm4543; - dma_addr_t dma_addr; - u32 mapped_nents = 0; - u32 dummy = 0; /*used for the assoc data fragments */ - u32 size_to_map = 0; - gfp_t flags = cc_gfp_flags(&req->base); - - mlli_params->curr_pool = NULL; - sg_data.num_of_buffers = 0; - - /* copy mac to a temporary location to deal with possible - * data memory overriding that caused by cache coherence problem. - */ - if (drvdata->coherent && - areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT && - req->src == req->dst) - cc_copy_mac(dev, req, CC_SG_TO_BUF); - - /* cacluate the size for cipher remove ICV in decrypt*/ - areq_ctx->cryptlen = (areq_ctx->gen_ctx.op_type == - DRV_CRYPTO_DIRECTION_ENCRYPT) ? - req->cryptlen : - (req->cryptlen - authsize); - - dma_addr = dma_map_single(dev, areq_ctx->mac_buf, MAX_MAC_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Mapping mac_buf %u B at va=%pK for DMA failed\n", - MAX_MAC_SIZE, areq_ctx->mac_buf); - rc = -ENOMEM; - goto aead_map_failure; - } - areq_ctx->mac_buf_dma_addr = dma_addr; - - if (areq_ctx->ccm_hdr_size != ccm_header_size_null) { - void *addr = areq_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET; - - dma_addr = dma_map_single(dev, addr, AES_BLOCK_SIZE, - DMA_TO_DEVICE); - - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Mapping mac_buf %u B at va=%pK for DMA failed\n", - AES_BLOCK_SIZE, addr); - areq_ctx->ccm_iv0_dma_addr = 0; - rc = -ENOMEM; - goto aead_map_failure; - } - areq_ctx->ccm_iv0_dma_addr = dma_addr; - - if (cc_set_aead_conf_buf(dev, areq_ctx, areq_ctx->ccm_config, - &sg_data, req->assoclen)) { - rc = -ENOMEM; - goto aead_map_failure; - } - } - - if (areq_ctx->cipher_mode == DRV_CIPHER_GCTR) { - dma_addr = dma_map_single(dev, areq_ctx->hkey, AES_BLOCK_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Mapping hkey %u B at va=%pK for DMA failed\n", - AES_BLOCK_SIZE, areq_ctx->hkey); - rc = -ENOMEM; - goto aead_map_failure; - } - areq_ctx->hkey_dma_addr = dma_addr; - - dma_addr = dma_map_single(dev, &areq_ctx->gcm_len_block, - AES_BLOCK_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Mapping gcm_len_block %u B at va=%pK for DMA failed\n", - AES_BLOCK_SIZE, &areq_ctx->gcm_len_block); - rc = -ENOMEM; - goto aead_map_failure; - } - areq_ctx->gcm_block_len_dma_addr = dma_addr; - - dma_addr = dma_map_single(dev, areq_ctx->gcm_iv_inc1, - AES_BLOCK_SIZE, DMA_TO_DEVICE); - - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Mapping gcm_iv_inc1 %u B at va=%pK for DMA failed\n", - AES_BLOCK_SIZE, (areq_ctx->gcm_iv_inc1)); - areq_ctx->gcm_iv_inc1_dma_addr = 0; - rc = -ENOMEM; - goto aead_map_failure; - } - areq_ctx->gcm_iv_inc1_dma_addr = dma_addr; - - dma_addr = dma_map_single(dev, areq_ctx->gcm_iv_inc2, - AES_BLOCK_SIZE, DMA_TO_DEVICE); - - if (dma_mapping_error(dev, dma_addr)) { - dev_err(dev, "Mapping gcm_iv_inc2 %u B at va=%pK for DMA failed\n", - AES_BLOCK_SIZE, (areq_ctx->gcm_iv_inc2)); - areq_ctx->gcm_iv_inc2_dma_addr = 0; - rc = -ENOMEM; - goto aead_map_failure; - } - areq_ctx->gcm_iv_inc2_dma_addr = dma_addr; - } - - size_to_map = req->cryptlen + req->assoclen; - if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT) - size_to_map += authsize; - - if (is_gcm4543) - size_to_map += crypto_aead_ivsize(tfm); - rc = cc_map_sg(dev, req->src, size_to_map, DMA_BIDIRECTIONAL, - &areq_ctx->src.nents, - (LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES + - LLI_MAX_NUM_OF_DATA_ENTRIES), - &dummy, &mapped_nents); - if (rc) { - rc = -ENOMEM; - goto aead_map_failure; - } - - if (areq_ctx->is_single_pass) { - /* - * Create MLLI table for: - * (1) Assoc. data - * (2) Src/Dst SGLs - * Note: IV is contg. buffer (not an SGL) - */ - rc = cc_aead_chain_assoc(drvdata, req, &sg_data, true, false); - if (rc) - goto aead_map_failure; - rc = cc_aead_chain_iv(drvdata, req, &sg_data, true, false); - if (rc) - goto aead_map_failure; - rc = cc_aead_chain_data(drvdata, req, &sg_data, true, false); - if (rc) - goto aead_map_failure; - } else { /* DOUBLE-PASS flow */ - /* - * Prepare MLLI table(s) in this order: - * - * If ENCRYPT/DECRYPT (inplace): - * (1) MLLI table for assoc - * (2) IV entry (chained right after end of assoc) - * (3) MLLI for src/dst (inplace operation) - * - * If ENCRYPT (non-inplace) - * (1) MLLI table for assoc - * (2) IV entry (chained right after end of assoc) - * (3) MLLI for dst - * (4) MLLI for src - * - * If DECRYPT (non-inplace) - * (1) MLLI table for assoc - * (2) IV entry (chained right after end of assoc) - * (3) MLLI for src - * (4) MLLI for dst - */ - rc = cc_aead_chain_assoc(drvdata, req, &sg_data, false, true); - if (rc) - goto aead_map_failure; - rc = cc_aead_chain_iv(drvdata, req, &sg_data, false, true); - if (rc) - goto aead_map_failure; - rc = cc_aead_chain_data(drvdata, req, &sg_data, true, true); - if (rc) - goto aead_map_failure; - } - - /* Mlli support -start building the MLLI according to the above - * results - */ - if (areq_ctx->assoc_buff_type == CC_DMA_BUF_MLLI || - areq_ctx->data_buff_type == CC_DMA_BUF_MLLI) { - mlli_params->curr_pool = buff_mgr->mlli_buffs_pool; - rc = cc_generate_mlli(dev, &sg_data, mlli_params, flags); - if (rc) - goto aead_map_failure; - - cc_update_aead_mlli_nents(drvdata, req); - dev_dbg(dev, "assoc params mn %d\n", - areq_ctx->assoc.mlli_nents); - dev_dbg(dev, "src params mn %d\n", areq_ctx->src.mlli_nents); - dev_dbg(dev, "dst params mn %d\n", areq_ctx->dst.mlli_nents); - } - return 0; - -aead_map_failure: - cc_unmap_aead_request(dev, req); - return rc; -} - -int cc_map_hash_request_final(struct cc_drvdata *drvdata, void *ctx, - struct scatterlist *src, unsigned int nbytes, - bool do_update, gfp_t flags) -{ - struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx; - struct device *dev = drvdata_to_dev(drvdata); - u8 *curr_buff = cc_hash_buf(areq_ctx); - u32 *curr_buff_cnt = cc_hash_buf_cnt(areq_ctx); - struct mlli_params *mlli_params = &areq_ctx->mlli_params; - struct buffer_array sg_data; - struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle; - u32 dummy = 0; - u32 mapped_nents = 0; - - dev_dbg(dev, "final params : curr_buff=%pK curr_buff_cnt=0x%X nbytes = 0x%X src=%pK curr_index=%u\n", - curr_buff, *curr_buff_cnt, nbytes, src, areq_ctx->buff_index); - /* Init the type of the dma buffer */ - areq_ctx->data_dma_buf_type = CC_DMA_BUF_NULL; - mlli_params->curr_pool = NULL; - sg_data.num_of_buffers = 0; - areq_ctx->in_nents = 0; - - if (nbytes == 0 && *curr_buff_cnt == 0) { - /* nothing to do */ - return 0; - } - - /*TODO: copy data in case that buffer is enough for operation */ - /* map the previous buffer */ - if (*curr_buff_cnt) { - if (cc_set_hash_buf(dev, areq_ctx, curr_buff, *curr_buff_cnt, - &sg_data)) { - return -ENOMEM; - } - } - - if (src && nbytes > 0 && do_update) { - if (cc_map_sg(dev, src, nbytes, DMA_TO_DEVICE, - &areq_ctx->in_nents, LLI_MAX_NUM_OF_DATA_ENTRIES, - &dummy, &mapped_nents)) { - goto unmap_curr_buff; - } - if (src && mapped_nents == 1 && - areq_ctx->data_dma_buf_type == CC_DMA_BUF_NULL) { - memcpy(areq_ctx->buff_sg, src, - sizeof(struct scatterlist)); - areq_ctx->buff_sg->length = nbytes; - areq_ctx->curr_sg = areq_ctx->buff_sg; - areq_ctx->data_dma_buf_type = CC_DMA_BUF_DLLI; - } else { - areq_ctx->data_dma_buf_type = CC_DMA_BUF_MLLI; - } - } - - /*build mlli */ - if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_MLLI) { - mlli_params->curr_pool = buff_mgr->mlli_buffs_pool; - /* add the src data to the sg_data */ - cc_add_sg_entry(dev, &sg_data, areq_ctx->in_nents, src, nbytes, - 0, true, &areq_ctx->mlli_nents); - if (cc_generate_mlli(dev, &sg_data, mlli_params, flags)) - goto fail_unmap_din; - } - /* change the buffer index for the unmap function */ - areq_ctx->buff_index = (areq_ctx->buff_index ^ 1); - dev_dbg(dev, "areq_ctx->data_dma_buf_type = %s\n", - cc_dma_buf_type(areq_ctx->data_dma_buf_type)); - return 0; - -fail_unmap_din: - dma_unmap_sg(dev, src, areq_ctx->in_nents, DMA_TO_DEVICE); - -unmap_curr_buff: - if (*curr_buff_cnt) - dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE); - - return -ENOMEM; -} - -int cc_map_hash_request_update(struct cc_drvdata *drvdata, void *ctx, - struct scatterlist *src, unsigned int nbytes, - unsigned int block_size, gfp_t flags) -{ - struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx; - struct device *dev = drvdata_to_dev(drvdata); - u8 *curr_buff = cc_hash_buf(areq_ctx); - u32 *curr_buff_cnt = cc_hash_buf_cnt(areq_ctx); - u8 *next_buff = cc_next_buf(areq_ctx); - u32 *next_buff_cnt = cc_next_buf_cnt(areq_ctx); - struct mlli_params *mlli_params = &areq_ctx->mlli_params; - unsigned int update_data_len; - u32 total_in_len = nbytes + *curr_buff_cnt; - struct buffer_array sg_data; - struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle; - unsigned int swap_index = 0; - u32 dummy = 0; - u32 mapped_nents = 0; - - dev_dbg(dev, " update params : curr_buff=%pK curr_buff_cnt=0x%X nbytes=0x%X src=%pK curr_index=%u\n", - curr_buff, *curr_buff_cnt, nbytes, src, areq_ctx->buff_index); - /* Init the type of the dma buffer */ - areq_ctx->data_dma_buf_type = CC_DMA_BUF_NULL; - mlli_params->curr_pool = NULL; - areq_ctx->curr_sg = NULL; - sg_data.num_of_buffers = 0; - areq_ctx->in_nents = 0; - - if (total_in_len < block_size) { - dev_dbg(dev, " less than one block: curr_buff=%pK *curr_buff_cnt=0x%X copy_to=%pK\n", - curr_buff, *curr_buff_cnt, &curr_buff[*curr_buff_cnt]); - areq_ctx->in_nents = - cc_get_sgl_nents(dev, src, nbytes, &dummy, NULL); - sg_copy_to_buffer(src, areq_ctx->in_nents, - &curr_buff[*curr_buff_cnt], nbytes); - *curr_buff_cnt += nbytes; - return 1; - } - - /* Calculate the residue size*/ - *next_buff_cnt = total_in_len & (block_size - 1); - /* update data len */ - update_data_len = total_in_len - *next_buff_cnt; - - dev_dbg(dev, " temp length : *next_buff_cnt=0x%X update_data_len=0x%X\n", - *next_buff_cnt, update_data_len); - - /* Copy the new residue to next buffer */ - if (*next_buff_cnt) { - dev_dbg(dev, " handle residue: next buff %pK skip data %u residue %u\n", - next_buff, (update_data_len - *curr_buff_cnt), - *next_buff_cnt); - cc_copy_sg_portion(dev, next_buff, src, - (update_data_len - *curr_buff_cnt), - nbytes, CC_SG_TO_BUF); - /* change the buffer index for next operation */ - swap_index = 1; - } - - if (*curr_buff_cnt) { - if (cc_set_hash_buf(dev, areq_ctx, curr_buff, *curr_buff_cnt, - &sg_data)) { - return -ENOMEM; - } - /* change the buffer index for next operation */ - swap_index = 1; - } - - if (update_data_len > *curr_buff_cnt) { - if (cc_map_sg(dev, src, (update_data_len - *curr_buff_cnt), - DMA_TO_DEVICE, &areq_ctx->in_nents, - LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, - &mapped_nents)) { - goto unmap_curr_buff; - } - if (mapped_nents == 1 && - areq_ctx->data_dma_buf_type == CC_DMA_BUF_NULL) { - /* only one entry in the SG and no previous data */ - memcpy(areq_ctx->buff_sg, src, - sizeof(struct scatterlist)); - areq_ctx->buff_sg->length = update_data_len; - areq_ctx->data_dma_buf_type = CC_DMA_BUF_DLLI; - areq_ctx->curr_sg = areq_ctx->buff_sg; - } else { - areq_ctx->data_dma_buf_type = CC_DMA_BUF_MLLI; - } - } - - if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_MLLI) { - mlli_params->curr_pool = buff_mgr->mlli_buffs_pool; - /* add the src data to the sg_data */ - cc_add_sg_entry(dev, &sg_data, areq_ctx->in_nents, src, - (update_data_len - *curr_buff_cnt), 0, true, - &areq_ctx->mlli_nents); - if (cc_generate_mlli(dev, &sg_data, mlli_params, flags)) - goto fail_unmap_din; - } - areq_ctx->buff_index = (areq_ctx->buff_index ^ swap_index); - - return 0; - -fail_unmap_din: - dma_unmap_sg(dev, src, areq_ctx->in_nents, DMA_TO_DEVICE); - -unmap_curr_buff: - if (*curr_buff_cnt) - dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE); - - return -ENOMEM; -} - -void cc_unmap_hash_request(struct device *dev, void *ctx, - struct scatterlist *src, bool do_revert) -{ - struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx; - u32 *prev_len = cc_next_buf_cnt(areq_ctx); - - /*In case a pool was set, a table was - *allocated and should be released - */ - if (areq_ctx->mlli_params.curr_pool) { - dev_dbg(dev, "free MLLI buffer: dma=%pad virt=%pK\n", - &areq_ctx->mlli_params.mlli_dma_addr, - areq_ctx->mlli_params.mlli_virt_addr); - dma_pool_free(areq_ctx->mlli_params.curr_pool, - areq_ctx->mlli_params.mlli_virt_addr, - areq_ctx->mlli_params.mlli_dma_addr); - } - - if (src && areq_ctx->in_nents) { - dev_dbg(dev, "Unmapped sg src: virt=%pK dma=%pad len=0x%X\n", - sg_virt(src), &sg_dma_address(src), sg_dma_len(src)); - dma_unmap_sg(dev, src, - areq_ctx->in_nents, DMA_TO_DEVICE); - } - - if (*prev_len) { - dev_dbg(dev, "Unmapped buffer: areq_ctx->buff_sg=%pK dma=%pad len 0x%X\n", - sg_virt(areq_ctx->buff_sg), - &sg_dma_address(areq_ctx->buff_sg), - sg_dma_len(areq_ctx->buff_sg)); - dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE); - if (!do_revert) { - /* clean the previous data length for update - * operation - */ - *prev_len = 0; - } else { - areq_ctx->buff_index ^= 1; - } - } -} - -int cc_buffer_mgr_init(struct cc_drvdata *drvdata) -{ - struct buff_mgr_handle *buff_mgr_handle; - struct device *dev = drvdata_to_dev(drvdata); - - buff_mgr_handle = kmalloc(sizeof(*buff_mgr_handle), GFP_KERNEL); - if (!buff_mgr_handle) - return -ENOMEM; - - drvdata->buff_mgr_handle = buff_mgr_handle; - - buff_mgr_handle->mlli_buffs_pool = - dma_pool_create("dx_single_mlli_tables", dev, - MAX_NUM_OF_TOTAL_MLLI_ENTRIES * - LLI_ENTRY_BYTE_SIZE, - MLLI_TABLE_MIN_ALIGNMENT, 0); - - if (!buff_mgr_handle->mlli_buffs_pool) - goto error; - - return 0; - -error: - cc_buffer_mgr_fini(drvdata); - return -ENOMEM; -} - -int cc_buffer_mgr_fini(struct cc_drvdata *drvdata) -{ - struct buff_mgr_handle *buff_mgr_handle = drvdata->buff_mgr_handle; - - if (buff_mgr_handle) { - dma_pool_destroy(buff_mgr_handle->mlli_buffs_pool); - kfree(drvdata->buff_mgr_handle); - drvdata->buff_mgr_handle = NULL; - } - return 0; -} diff --git a/drivers/staging/ccree/cc_buffer_mgr.h b/drivers/staging/ccree/cc_buffer_mgr.h deleted file mode 100644 index 99b752aa1077..000000000000 --- a/drivers/staging/ccree/cc_buffer_mgr.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -/* \file cc_buffer_mgr.h - * Buffer Manager - */ - -#ifndef __CC_BUFFER_MGR_H__ -#define __CC_BUFFER_MGR_H__ - -#include <crypto/algapi.h> - -#include "cc_driver.h" - -enum cc_req_dma_buf_type { - CC_DMA_BUF_NULL = 0, - CC_DMA_BUF_DLLI, - CC_DMA_BUF_MLLI -}; - -enum cc_sg_cpy_direct { - CC_SG_TO_BUF = 0, - CC_SG_FROM_BUF = 1 -}; - -struct cc_mlli { - cc_sram_addr_t sram_addr; - unsigned int nents; //sg nents - unsigned int mlli_nents; //mlli nents might be different than the above -}; - -struct mlli_params { - struct dma_pool *curr_pool; - u8 *mlli_virt_addr; - dma_addr_t mlli_dma_addr; - u32 mlli_len; -}; - -int cc_buffer_mgr_init(struct cc_drvdata *drvdata); - -int cc_buffer_mgr_fini(struct cc_drvdata *drvdata); - -int cc_map_blkcipher_request(struct cc_drvdata *drvdata, void *ctx, - unsigned int ivsize, unsigned int nbytes, - void *info, struct scatterlist *src, - struct scatterlist *dst, gfp_t flags); - -void cc_unmap_blkcipher_request(struct device *dev, void *ctx, - unsigned int ivsize, - struct scatterlist *src, - struct scatterlist *dst); - -int cc_map_aead_request(struct cc_drvdata *drvdata, struct aead_request *req); - -void cc_unmap_aead_request(struct device *dev, struct aead_request *req); - -int cc_map_hash_request_final(struct cc_drvdata *drvdata, void *ctx, - struct scatterlist *src, unsigned int nbytes, - bool do_update, gfp_t flags); - -int cc_map_hash_request_update(struct cc_drvdata *drvdata, void *ctx, - struct scatterlist *src, unsigned int nbytes, - unsigned int block_size, gfp_t flags); - -void cc_unmap_hash_request(struct device *dev, void *ctx, - struct scatterlist *src, bool do_revert); - -void cc_copy_sg_portion(struct device *dev, u8 *dest, struct scatterlist *sg, - u32 to_skip, u32 end, enum cc_sg_cpy_direct direct); - -void cc_zero_sgl(struct scatterlist *sgl, u32 data_len); - -#endif /*__BUFFER_MGR_H__*/ - diff --git a/drivers/staging/ccree/cc_cipher.c b/drivers/staging/ccree/cc_cipher.c deleted file mode 100644 index d4ac0ff2ffcf..000000000000 --- a/drivers/staging/ccree/cc_cipher.c +++ /dev/null @@ -1,1164 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <crypto/algapi.h> -#include <crypto/internal/skcipher.h> -#include <crypto/des.h> -#include <crypto/xts.h> -#include <crypto/scatterwalk.h> - -#include "cc_driver.h" -#include "cc_lli_defs.h" -#include "cc_buffer_mgr.h" -#include "cc_cipher.h" -#include "cc_request_mgr.h" - -#define MAX_ABLKCIPHER_SEQ_LEN 6 - -#define template_ablkcipher template_u.ablkcipher - -#define CC_MIN_AES_XTS_SIZE 0x10 -#define CC_MAX_AES_XTS_SIZE 0x2000 -struct cc_cipher_handle { - struct list_head blkcipher_alg_list; -}; - -struct cc_user_key_info { - u8 *key; - dma_addr_t key_dma_addr; -}; - -struct cc_hw_key_info { - enum cc_hw_crypto_key key1_slot; - enum cc_hw_crypto_key key2_slot; -}; - -struct cc_cipher_ctx { - struct cc_drvdata *drvdata; - int keylen; - int key_round_number; - int cipher_mode; - int flow_mode; - unsigned int flags; - struct blkcipher_req_ctx *sync_ctx; - struct cc_user_key_info user; - struct cc_hw_key_info hw; - struct crypto_shash *shash_tfm; -}; - -static void cc_cipher_complete(struct device *dev, void *cc_req, int err); - -static int validate_keys_sizes(struct cc_cipher_ctx *ctx_p, u32 size) -{ - switch (ctx_p->flow_mode) { - case S_DIN_to_AES: - switch (size) { - case CC_AES_128_BIT_KEY_SIZE: - case CC_AES_192_BIT_KEY_SIZE: - if (ctx_p->cipher_mode != DRV_CIPHER_XTS && - ctx_p->cipher_mode != DRV_CIPHER_ESSIV && - ctx_p->cipher_mode != DRV_CIPHER_BITLOCKER) - return 0; - break; - case CC_AES_256_BIT_KEY_SIZE: - return 0; - case (CC_AES_192_BIT_KEY_SIZE * 2): - case (CC_AES_256_BIT_KEY_SIZE * 2): - if (ctx_p->cipher_mode == DRV_CIPHER_XTS || - ctx_p->cipher_mode == DRV_CIPHER_ESSIV || - ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) - return 0; - break; - default: - break; - } - case S_DIN_to_DES: - if (size == DES3_EDE_KEY_SIZE || size == DES_KEY_SIZE) - return 0; - break; - default: - break; - } - return -EINVAL; -} - -static int validate_data_size(struct cc_cipher_ctx *ctx_p, - unsigned int size) -{ - switch (ctx_p->flow_mode) { - case S_DIN_to_AES: - switch (ctx_p->cipher_mode) { - case DRV_CIPHER_XTS: - if (size >= CC_MIN_AES_XTS_SIZE && - size <= CC_MAX_AES_XTS_SIZE && - IS_ALIGNED(size, AES_BLOCK_SIZE)) - return 0; - break; - case DRV_CIPHER_CBC_CTS: - if (size >= AES_BLOCK_SIZE) - return 0; - break; - case DRV_CIPHER_OFB: - case DRV_CIPHER_CTR: - return 0; - case DRV_CIPHER_ECB: - case DRV_CIPHER_CBC: - case DRV_CIPHER_ESSIV: - case DRV_CIPHER_BITLOCKER: - if (IS_ALIGNED(size, AES_BLOCK_SIZE)) - return 0; - break; - default: - break; - } - break; - case S_DIN_to_DES: - if (IS_ALIGNED(size, DES_BLOCK_SIZE)) - return 0; - break; - default: - break; - } - return -EINVAL; -} - -static unsigned int get_max_keysize(struct crypto_tfm *tfm) -{ - struct cc_crypto_alg *cc_alg = - container_of(tfm->__crt_alg, struct cc_crypto_alg, crypto_alg); - - if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_ABLKCIPHER) - return cc_alg->crypto_alg.cra_ablkcipher.max_keysize; - - if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_BLKCIPHER) - return cc_alg->crypto_alg.cra_blkcipher.max_keysize; - - return 0; -} - -static int cc_cipher_init(struct crypto_tfm *tfm) -{ - struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); - struct crypto_alg *alg = tfm->__crt_alg; - struct cc_crypto_alg *cc_alg = - container_of(alg, struct cc_crypto_alg, crypto_alg); - struct device *dev = drvdata_to_dev(cc_alg->drvdata); - int rc = 0; - unsigned int max_key_buf_size = get_max_keysize(tfm); - struct ablkcipher_tfm *ablktfm = &tfm->crt_ablkcipher; - - dev_dbg(dev, "Initializing context @%p for %s\n", ctx_p, - crypto_tfm_alg_name(tfm)); - - ablktfm->reqsize = sizeof(struct blkcipher_req_ctx); - - ctx_p->cipher_mode = cc_alg->cipher_mode; - ctx_p->flow_mode = cc_alg->flow_mode; - ctx_p->drvdata = cc_alg->drvdata; - - /* Allocate key buffer, cache line aligned */ - ctx_p->user.key = kmalloc(max_key_buf_size, GFP_KERNEL); - if (!ctx_p->user.key) - return -ENOMEM; - - dev_dbg(dev, "Allocated key buffer in context. key=@%p\n", - ctx_p->user.key); - - /* Map key buffer */ - ctx_p->user.key_dma_addr = dma_map_single(dev, (void *)ctx_p->user.key, - max_key_buf_size, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, ctx_p->user.key_dma_addr)) { - dev_err(dev, "Mapping Key %u B at va=%pK for DMA failed\n", - max_key_buf_size, ctx_p->user.key); - return -ENOMEM; - } - dev_dbg(dev, "Mapped key %u B at va=%pK to dma=%pad\n", - max_key_buf_size, ctx_p->user.key, &ctx_p->user.key_dma_addr); - - if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { - /* Alloc hash tfm for essiv */ - ctx_p->shash_tfm = crypto_alloc_shash("sha256-generic", 0, 0); - if (IS_ERR(ctx_p->shash_tfm)) { - dev_err(dev, "Error allocating hash tfm for ESSIV.\n"); - return PTR_ERR(ctx_p->shash_tfm); - } - } - - return rc; -} - -static void cc_cipher_exit(struct crypto_tfm *tfm) -{ - struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx_p->drvdata); - unsigned int max_key_buf_size = get_max_keysize(tfm); - - dev_dbg(dev, "Clearing context @%p for %s\n", - crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm)); - - if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { - /* Free hash tfm for essiv */ - crypto_free_shash(ctx_p->shash_tfm); - ctx_p->shash_tfm = NULL; - } - - /* Unmap key buffer */ - dma_unmap_single(dev, ctx_p->user.key_dma_addr, max_key_buf_size, - DMA_TO_DEVICE); - dev_dbg(dev, "Unmapped key buffer key_dma_addr=%pad\n", - &ctx_p->user.key_dma_addr); - - /* Free key buffer in context */ - kfree(ctx_p->user.key); - dev_dbg(dev, "Free key buffer in context. key=@%p\n", ctx_p->user.key); -} - -struct tdes_keys { - u8 key1[DES_KEY_SIZE]; - u8 key2[DES_KEY_SIZE]; - u8 key3[DES_KEY_SIZE]; -}; - -static const u8 zero_buff[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - -/* The function verifies that tdes keys are not weak.*/ -static int cc_verify_3des_keys(const u8 *key, unsigned int keylen) -{ - struct tdes_keys *tdes_key = (struct tdes_keys *)key; - - /* verify key1 != key2 and key3 != key2*/ - if ((memcmp((u8 *)tdes_key->key1, (u8 *)tdes_key->key2, - sizeof(tdes_key->key1)) == 0) || - (memcmp((u8 *)tdes_key->key3, (u8 *)tdes_key->key2, - sizeof(tdes_key->key3)) == 0)) { - return -ENOEXEC; - } - - return 0; -} - -static enum cc_hw_crypto_key hw_key_to_cc_hw_key(int slot_num) -{ - switch (slot_num) { - case 0: - return KFDE0_KEY; - case 1: - return KFDE1_KEY; - case 2: - return KFDE2_KEY; - case 3: - return KFDE3_KEY; - } - return END_OF_KEYS; -} - -static int cc_cipher_setkey(struct crypto_ablkcipher *atfm, const u8 *key, - unsigned int keylen) -{ - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(atfm); - struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx_p->drvdata); - u32 tmp[DES_EXPKEY_WORDS]; - unsigned int max_key_buf_size = get_max_keysize(tfm); - - dev_dbg(dev, "Setting key in context @%p for %s. keylen=%u\n", - ctx_p, crypto_tfm_alg_name(tfm), keylen); - dump_byte_array("key", (u8 *)key, keylen); - - /* STAT_PHASE_0: Init and sanity checks */ - - if (validate_keys_sizes(ctx_p, keylen)) { - dev_err(dev, "Unsupported key size %d.\n", keylen); - crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - if (cc_is_hw_key(tfm)) { - /* setting HW key slots */ - struct arm_hw_key_info *hki = (struct arm_hw_key_info *)key; - - if (ctx_p->flow_mode != S_DIN_to_AES) { - dev_err(dev, "HW key not supported for non-AES flows\n"); - return -EINVAL; - } - - ctx_p->hw.key1_slot = hw_key_to_cc_hw_key(hki->hw_key1); - if (ctx_p->hw.key1_slot == END_OF_KEYS) { - dev_err(dev, "Unsupported hw key1 number (%d)\n", - hki->hw_key1); - return -EINVAL; - } - - if (ctx_p->cipher_mode == DRV_CIPHER_XTS || - ctx_p->cipher_mode == DRV_CIPHER_ESSIV || - ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER) { - if (hki->hw_key1 == hki->hw_key2) { - dev_err(dev, "Illegal hw key numbers (%d,%d)\n", - hki->hw_key1, hki->hw_key2); - return -EINVAL; - } - ctx_p->hw.key2_slot = - hw_key_to_cc_hw_key(hki->hw_key2); - if (ctx_p->hw.key2_slot == END_OF_KEYS) { - dev_err(dev, "Unsupported hw key2 number (%d)\n", - hki->hw_key2); - return -EINVAL; - } - } - - ctx_p->keylen = keylen; - dev_dbg(dev, "cc_is_hw_key ret 0"); - - return 0; - } - - // verify weak keys - if (ctx_p->flow_mode == S_DIN_to_DES) { - if (!des_ekey(tmp, key) && - (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_WEAK_KEY)) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - dev_dbg(dev, "weak DES key"); - return -EINVAL; - } - } - if (ctx_p->cipher_mode == DRV_CIPHER_XTS && - xts_check_key(tfm, key, keylen)) { - dev_dbg(dev, "weak XTS key"); - return -EINVAL; - } - if (ctx_p->flow_mode == S_DIN_to_DES && - keylen == DES3_EDE_KEY_SIZE && - cc_verify_3des_keys(key, keylen)) { - dev_dbg(dev, "weak 3DES key"); - return -EINVAL; - } - - /* STAT_PHASE_1: Copy key to ctx */ - dma_sync_single_for_cpu(dev, ctx_p->user.key_dma_addr, - max_key_buf_size, DMA_TO_DEVICE); - - memcpy(ctx_p->user.key, key, keylen); - if (keylen == 24) - memset(ctx_p->user.key + 24, 0, CC_AES_KEY_SIZE_MAX - 24); - - if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) { - /* sha256 for key2 - use sw implementation */ - int key_len = keylen >> 1; - int err; - - SHASH_DESC_ON_STACK(desc, ctx_p->shash_tfm); - - desc->tfm = ctx_p->shash_tfm; - - err = crypto_shash_digest(desc, ctx_p->user.key, key_len, - ctx_p->user.key + key_len); - if (err) { - dev_err(dev, "Failed to hash ESSIV key.\n"); - return err; - } - } - dma_sync_single_for_device(dev, ctx_p->user.key_dma_addr, - max_key_buf_size, DMA_TO_DEVICE); - ctx_p->keylen = keylen; - - dev_dbg(dev, "return safely"); - return 0; -} - -static void cc_setup_cipher_desc(struct crypto_tfm *tfm, - struct blkcipher_req_ctx *req_ctx, - unsigned int ivsize, unsigned int nbytes, - struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx_p->drvdata); - int cipher_mode = ctx_p->cipher_mode; - int flow_mode = ctx_p->flow_mode; - int direction = req_ctx->gen_ctx.op_type; - dma_addr_t key_dma_addr = ctx_p->user.key_dma_addr; - unsigned int key_len = ctx_p->keylen; - dma_addr_t iv_dma_addr = req_ctx->gen_ctx.iv_dma_addr; - unsigned int du_size = nbytes; - - struct cc_crypto_alg *cc_alg = - container_of(tfm->__crt_alg, struct cc_crypto_alg, crypto_alg); - - if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_BULK_MASK) == - CRYPTO_ALG_BULK_DU_512) - du_size = 512; - if ((cc_alg->crypto_alg.cra_flags & CRYPTO_ALG_BULK_MASK) == - CRYPTO_ALG_BULK_DU_4096) - du_size = 4096; - - switch (cipher_mode) { - case DRV_CIPHER_CBC: - case DRV_CIPHER_CBC_CTS: - case DRV_CIPHER_CTR: - case DRV_CIPHER_OFB: - /* Load cipher state */ - hw_desc_init(&desc[*seq_size]); - set_din_type(&desc[*seq_size], DMA_DLLI, iv_dma_addr, ivsize, - NS_BIT); - set_cipher_config0(&desc[*seq_size], direction); - set_flow_mode(&desc[*seq_size], flow_mode); - set_cipher_mode(&desc[*seq_size], cipher_mode); - if (cipher_mode == DRV_CIPHER_CTR || - cipher_mode == DRV_CIPHER_OFB) { - set_setup_mode(&desc[*seq_size], SETUP_LOAD_STATE1); - } else { - set_setup_mode(&desc[*seq_size], SETUP_LOAD_STATE0); - } - (*seq_size)++; - /*FALLTHROUGH*/ - case DRV_CIPHER_ECB: - /* Load key */ - hw_desc_init(&desc[*seq_size]); - set_cipher_mode(&desc[*seq_size], cipher_mode); - set_cipher_config0(&desc[*seq_size], direction); - if (flow_mode == S_DIN_to_AES) { - if (cc_is_hw_key(tfm)) { - set_hw_crypto_key(&desc[*seq_size], - ctx_p->hw.key1_slot); - } else { - set_din_type(&desc[*seq_size], DMA_DLLI, - key_dma_addr, ((key_len == 24) ? - AES_MAX_KEY_SIZE : - key_len), NS_BIT); - } - set_key_size_aes(&desc[*seq_size], key_len); - } else { - /*des*/ - set_din_type(&desc[*seq_size], DMA_DLLI, key_dma_addr, - key_len, NS_BIT); - set_key_size_des(&desc[*seq_size], key_len); - } - set_flow_mode(&desc[*seq_size], flow_mode); - set_setup_mode(&desc[*seq_size], SETUP_LOAD_KEY0); - (*seq_size)++; - break; - case DRV_CIPHER_XTS: - case DRV_CIPHER_ESSIV: - case DRV_CIPHER_BITLOCKER: - /* Load AES key */ - hw_desc_init(&desc[*seq_size]); - set_cipher_mode(&desc[*seq_size], cipher_mode); - set_cipher_config0(&desc[*seq_size], direction); - if (cc_is_hw_key(tfm)) { - set_hw_crypto_key(&desc[*seq_size], - ctx_p->hw.key1_slot); - } else { - set_din_type(&desc[*seq_size], DMA_DLLI, key_dma_addr, - (key_len / 2), NS_BIT); - } - set_key_size_aes(&desc[*seq_size], (key_len / 2)); - set_flow_mode(&desc[*seq_size], flow_mode); - set_setup_mode(&desc[*seq_size], SETUP_LOAD_KEY0); - (*seq_size)++; - - /* load XEX key */ - hw_desc_init(&desc[*seq_size]); - set_cipher_mode(&desc[*seq_size], cipher_mode); - set_cipher_config0(&desc[*seq_size], direction); - if (cc_is_hw_key(tfm)) { - set_hw_crypto_key(&desc[*seq_size], - ctx_p->hw.key2_slot); - } else { - set_din_type(&desc[*seq_size], DMA_DLLI, - (key_dma_addr + (key_len / 2)), - (key_len / 2), NS_BIT); - } - set_xex_data_unit_size(&desc[*seq_size], du_size); - set_flow_mode(&desc[*seq_size], S_DIN_to_AES2); - set_key_size_aes(&desc[*seq_size], (key_len / 2)); - set_setup_mode(&desc[*seq_size], SETUP_LOAD_XEX_KEY); - (*seq_size)++; - - /* Set state */ - hw_desc_init(&desc[*seq_size]); - set_setup_mode(&desc[*seq_size], SETUP_LOAD_STATE1); - set_cipher_mode(&desc[*seq_size], cipher_mode); - set_cipher_config0(&desc[*seq_size], direction); - set_key_size_aes(&desc[*seq_size], (key_len / 2)); - set_flow_mode(&desc[*seq_size], flow_mode); - set_din_type(&desc[*seq_size], DMA_DLLI, iv_dma_addr, - CC_AES_BLOCK_SIZE, NS_BIT); - (*seq_size)++; - break; - default: - dev_err(dev, "Unsupported cipher mode (%d)\n", cipher_mode); - } -} - -static void cc_setup_cipher_data(struct crypto_tfm *tfm, - struct blkcipher_req_ctx *req_ctx, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes, - void *areq, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx_p->drvdata); - unsigned int flow_mode = ctx_p->flow_mode; - - switch (ctx_p->flow_mode) { - case S_DIN_to_AES: - flow_mode = DIN_AES_DOUT; - break; - case S_DIN_to_DES: - flow_mode = DIN_DES_DOUT; - break; - default: - dev_err(dev, "invalid flow mode, flow_mode = %d\n", flow_mode); - return; - } - /* Process */ - if (req_ctx->dma_buf_type == CC_DMA_BUF_DLLI) { - dev_dbg(dev, " data params addr %pad length 0x%X\n", - &sg_dma_address(src), nbytes); - dev_dbg(dev, " data params addr %pad length 0x%X\n", - &sg_dma_address(dst), nbytes); - hw_desc_init(&desc[*seq_size]); - set_din_type(&desc[*seq_size], DMA_DLLI, sg_dma_address(src), - nbytes, NS_BIT); - set_dout_dlli(&desc[*seq_size], sg_dma_address(dst), - nbytes, NS_BIT, (!areq ? 0 : 1)); - if (areq) - set_queue_last_ind(&desc[*seq_size]); - - set_flow_mode(&desc[*seq_size], flow_mode); - (*seq_size)++; - } else { - /* bypass */ - dev_dbg(dev, " bypass params addr %pad length 0x%X addr 0x%08X\n", - &req_ctx->mlli_params.mlli_dma_addr, - req_ctx->mlli_params.mlli_len, - (unsigned int)ctx_p->drvdata->mlli_sram_addr); - hw_desc_init(&desc[*seq_size]); - set_din_type(&desc[*seq_size], DMA_DLLI, - req_ctx->mlli_params.mlli_dma_addr, - req_ctx->mlli_params.mlli_len, NS_BIT); - set_dout_sram(&desc[*seq_size], - ctx_p->drvdata->mlli_sram_addr, - req_ctx->mlli_params.mlli_len); - set_flow_mode(&desc[*seq_size], BYPASS); - (*seq_size)++; - - hw_desc_init(&desc[*seq_size]); - set_din_type(&desc[*seq_size], DMA_MLLI, - ctx_p->drvdata->mlli_sram_addr, - req_ctx->in_mlli_nents, NS_BIT); - if (req_ctx->out_nents == 0) { - dev_dbg(dev, " din/dout params addr 0x%08X addr 0x%08X\n", - (unsigned int)ctx_p->drvdata->mlli_sram_addr, - (unsigned int)ctx_p->drvdata->mlli_sram_addr); - set_dout_mlli(&desc[*seq_size], - ctx_p->drvdata->mlli_sram_addr, - req_ctx->in_mlli_nents, NS_BIT, - (!areq ? 0 : 1)); - } else { - dev_dbg(dev, " din/dout params addr 0x%08X addr 0x%08X\n", - (unsigned int)ctx_p->drvdata->mlli_sram_addr, - (unsigned int)ctx_p->drvdata->mlli_sram_addr + - (u32)LLI_ENTRY_BYTE_SIZE * req_ctx->in_nents); - set_dout_mlli(&desc[*seq_size], - (ctx_p->drvdata->mlli_sram_addr + - (LLI_ENTRY_BYTE_SIZE * - req_ctx->in_mlli_nents)), - req_ctx->out_mlli_nents, NS_BIT, - (!areq ? 0 : 1)); - } - if (areq) - set_queue_last_ind(&desc[*seq_size]); - - set_flow_mode(&desc[*seq_size], flow_mode); - (*seq_size)++; - } -} - -static void cc_cipher_complete(struct device *dev, void *cc_req, int err) -{ - struct ablkcipher_request *areq = (struct ablkcipher_request *)cc_req; - struct scatterlist *dst = areq->dst; - struct scatterlist *src = areq->src; - struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(areq); - struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); - unsigned int ivsize = crypto_ablkcipher_ivsize(tfm); - struct ablkcipher_request *req = (struct ablkcipher_request *)areq; - - cc_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst); - kfree(req_ctx->iv); - - /* - * The crypto API expects us to set the req->info to the last - * ciphertext block. For encrypt, simply copy from the result. - * For decrypt, we must copy from a saved buffer since this - * could be an in-place decryption operation and the src is - * lost by this point. - */ - if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) { - memcpy(req->info, req_ctx->backup_info, ivsize); - kfree(req_ctx->backup_info); - } else if (!err) { - scatterwalk_map_and_copy(req->info, req->dst, - (req->nbytes - ivsize), ivsize, 0); - } - - ablkcipher_request_complete(areq, err); -} - -static int cc_cipher_process(struct ablkcipher_request *req, - enum drv_crypto_direction direction) -{ - struct crypto_ablkcipher *ablk_tfm = crypto_ablkcipher_reqtfm(req); - struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk_tfm); - struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); - unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm); - struct scatterlist *dst = req->dst; - struct scatterlist *src = req->src; - unsigned int nbytes = req->nbytes; - void *info = req->info; - struct cc_cipher_ctx *ctx_p = crypto_tfm_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx_p->drvdata); - struct cc_hw_desc desc[MAX_ABLKCIPHER_SEQ_LEN]; - struct cc_crypto_req cc_req = {}; - int rc, seq_len = 0, cts_restore_flag = 0; - gfp_t flags = cc_gfp_flags(&req->base); - - dev_dbg(dev, "%s req=%p info=%p nbytes=%d\n", - ((direction == DRV_CRYPTO_DIRECTION_ENCRYPT) ? - "Encrypt" : "Decrypt"), req, info, nbytes); - - /* STAT_PHASE_0: Init and sanity checks */ - - /* TODO: check data length according to mode */ - if (validate_data_size(ctx_p, nbytes)) { - dev_err(dev, "Unsupported data size %d.\n", nbytes); - crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN); - rc = -EINVAL; - goto exit_process; - } - if (nbytes == 0) { - /* No data to process is valid */ - rc = 0; - goto exit_process; - } - - /* The IV we are handed may be allocted from the stack so - * we must copy it to a DMAable buffer before use. - */ - req_ctx->iv = kmalloc(ivsize, flags); - if (!req_ctx->iv) { - rc = -ENOMEM; - goto exit_process; - } - memcpy(req_ctx->iv, info, ivsize); - - /*For CTS in case of data size aligned to 16 use CBC mode*/ - if (((nbytes % AES_BLOCK_SIZE) == 0) && - ctx_p->cipher_mode == DRV_CIPHER_CBC_CTS) { - ctx_p->cipher_mode = DRV_CIPHER_CBC; - cts_restore_flag = 1; - } - - /* Setup DX request structure */ - cc_req.user_cb = (void *)cc_cipher_complete; - cc_req.user_arg = (void *)req; - -#ifdef ENABLE_CYCLE_COUNT - cc_req.op_type = (direction == DRV_CRYPTO_DIRECTION_DECRYPT) ? - STAT_OP_TYPE_DECODE : STAT_OP_TYPE_ENCODE; - -#endif - - /* Setup request context */ - req_ctx->gen_ctx.op_type = direction; - - /* STAT_PHASE_1: Map buffers */ - - rc = cc_map_blkcipher_request(ctx_p->drvdata, req_ctx, ivsize, nbytes, - req_ctx->iv, src, dst, flags); - if (rc) { - dev_err(dev, "map_request() failed\n"); - goto exit_process; - } - - /* STAT_PHASE_2: Create sequence */ - - /* Setup processing */ - cc_setup_cipher_desc(tfm, req_ctx, ivsize, nbytes, desc, &seq_len); - /* Data processing */ - cc_setup_cipher_data(tfm, req_ctx, dst, src, nbytes, req, desc, - &seq_len); - - /* do we need to generate IV? */ - if (req_ctx->is_giv) { - cc_req.ivgen_dma_addr[0] = req_ctx->gen_ctx.iv_dma_addr; - cc_req.ivgen_dma_addr_len = 1; - /* set the IV size (8/16 B long)*/ - cc_req.ivgen_size = ivsize; - } - - /* STAT_PHASE_3: Lock HW and push sequence */ - - rc = cc_send_request(ctx_p->drvdata, &cc_req, desc, seq_len, - &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - /* Failed to send the request or request completed - * synchronously - */ - cc_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst); - } - -exit_process: - if (cts_restore_flag) - ctx_p->cipher_mode = DRV_CIPHER_CBC_CTS; - - if (rc != -EINPROGRESS && rc != -EBUSY) { - kfree(req_ctx->backup_info); - kfree(req_ctx->iv); - } - - return rc; -} - -static int cc_cipher_encrypt(struct ablkcipher_request *req) -{ - struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); - - req_ctx->is_giv = false; - req_ctx->backup_info = NULL; - - return cc_cipher_process(req, DRV_CRYPTO_DIRECTION_ENCRYPT); -} - -static int cc_cipher_decrypt(struct ablkcipher_request *req) -{ - struct crypto_ablkcipher *ablk_tfm = crypto_ablkcipher_reqtfm(req); - struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); - unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm); - gfp_t flags = cc_gfp_flags(&req->base); - - /* - * Allocate and save the last IV sized bytes of the source, which will - * be lost in case of in-place decryption and might be needed for CTS. - */ - req_ctx->backup_info = kmalloc(ivsize, flags); - if (!req_ctx->backup_info) - return -ENOMEM; - - scatterwalk_map_and_copy(req_ctx->backup_info, req->src, - (req->nbytes - ivsize), ivsize, 0); - req_ctx->is_giv = false; - - return cc_cipher_process(req, DRV_CRYPTO_DIRECTION_DECRYPT); -} - -/* DX Block cipher alg */ -static struct cc_alg_template blkcipher_algs[] = { - { - .name = "xts(aes)", - .driver_name = "xts-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - .geniv = "eseqiv", - }, - .cipher_mode = DRV_CIPHER_XTS, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "xts(aes)", - .driver_name = "xts-aes-du512-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_XTS, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "xts(aes)", - .driver_name = "xts-aes-du4096-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_XTS, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "essiv(aes)", - .driver_name = "essiv-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_ESSIV, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "essiv(aes)", - .driver_name = "essiv-aes-du512-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_ESSIV, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "essiv(aes)", - .driver_name = "essiv-aes-du4096-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_ESSIV, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "bitlocker(aes)", - .driver_name = "bitlocker-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_BITLOCKER, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "bitlocker(aes)", - .driver_name = "bitlocker-aes-du512-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_BITLOCKER, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "bitlocker(aes)", - .driver_name = "bitlocker-aes-du4096-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE * 2, - .max_keysize = AES_MAX_KEY_SIZE * 2, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_BITLOCKER, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "ecb(aes)", - .driver_name = "ecb-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = 0, - }, - .cipher_mode = DRV_CIPHER_ECB, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "cbc(aes)", - .driver_name = "cbc-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "ofb(aes)", - .driver_name = "ofb-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_OFB, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "cts1(cbc(aes))", - .driver_name = "cts1-cbc-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC_CTS, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "ctr(aes)", - .driver_name = "ctr-aes-dx", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CTR, - .flow_mode = S_DIN_to_AES, - }, - { - .name = "cbc(des3_ede)", - .driver_name = "cbc-3des-dx", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_DES, - }, - { - .name = "ecb(des3_ede)", - .driver_name = "ecb-3des-dx", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = 0, - }, - .cipher_mode = DRV_CIPHER_ECB, - .flow_mode = S_DIN_to_DES, - }, - { - .name = "cbc(des)", - .driver_name = "cbc-des-dx", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_CBC, - .flow_mode = S_DIN_to_DES, - }, - { - .name = "ecb(des)", - .driver_name = "ecb-des-dx", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = 0, - }, - .cipher_mode = DRV_CIPHER_ECB, - .flow_mode = S_DIN_to_DES, - }, -}; - -static -struct cc_crypto_alg *cc_cipher_create_alg(struct cc_alg_template *template, - struct device *dev) -{ - struct cc_crypto_alg *t_alg; - struct crypto_alg *alg; - - t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); - if (!t_alg) - return ERR_PTR(-ENOMEM); - - alg = &t_alg->crypto_alg; - - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->driver_name); - alg->cra_module = THIS_MODULE; - alg->cra_priority = CC_CRA_PRIO; - alg->cra_blocksize = template->blocksize; - alg->cra_alignmask = 0; - alg->cra_ctxsize = sizeof(struct cc_cipher_ctx); - - alg->cra_init = cc_cipher_init; - alg->cra_exit = cc_cipher_exit; - alg->cra_type = &crypto_ablkcipher_type; - alg->cra_ablkcipher = template->template_ablkcipher; - alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - template->type; - - t_alg->cipher_mode = template->cipher_mode; - t_alg->flow_mode = template->flow_mode; - - return t_alg; -} - -int cc_cipher_free(struct cc_drvdata *drvdata) -{ - struct cc_crypto_alg *t_alg, *n; - struct cc_cipher_handle *blkcipher_handle = drvdata->blkcipher_handle; - - if (blkcipher_handle) { - /* Remove registered algs */ - list_for_each_entry_safe(t_alg, n, - &blkcipher_handle->blkcipher_alg_list, - entry) { - crypto_unregister_alg(&t_alg->crypto_alg); - list_del(&t_alg->entry); - kfree(t_alg); - } - kfree(blkcipher_handle); - drvdata->blkcipher_handle = NULL; - } - return 0; -} - -int cc_cipher_alloc(struct cc_drvdata *drvdata) -{ - struct cc_cipher_handle *ablkcipher_handle; - struct cc_crypto_alg *t_alg; - struct device *dev = drvdata_to_dev(drvdata); - int rc = -ENOMEM; - int alg; - - ablkcipher_handle = kmalloc(sizeof(*ablkcipher_handle), GFP_KERNEL); - if (!ablkcipher_handle) - return -ENOMEM; - - INIT_LIST_HEAD(&ablkcipher_handle->blkcipher_alg_list); - drvdata->blkcipher_handle = ablkcipher_handle; - - /* Linux crypto */ - dev_dbg(dev, "Number of algorithms = %zu\n", - ARRAY_SIZE(blkcipher_algs)); - for (alg = 0; alg < ARRAY_SIZE(blkcipher_algs); alg++) { - dev_dbg(dev, "creating %s\n", blkcipher_algs[alg].driver_name); - t_alg = cc_cipher_create_alg(&blkcipher_algs[alg], dev); - if (IS_ERR(t_alg)) { - rc = PTR_ERR(t_alg); - dev_err(dev, "%s alg allocation failed\n", - blkcipher_algs[alg].driver_name); - goto fail0; - } - t_alg->drvdata = drvdata; - - dev_dbg(dev, "registering %s\n", - blkcipher_algs[alg].driver_name); - rc = crypto_register_alg(&t_alg->crypto_alg); - dev_dbg(dev, "%s alg registration rc = %x\n", - t_alg->crypto_alg.cra_driver_name, rc); - if (rc) { - dev_err(dev, "%s alg registration failed\n", - t_alg->crypto_alg.cra_driver_name); - kfree(t_alg); - goto fail0; - } else { - list_add_tail(&t_alg->entry, - &ablkcipher_handle->blkcipher_alg_list); - dev_dbg(dev, "Registered %s\n", - t_alg->crypto_alg.cra_driver_name); - } - } - return 0; - -fail0: - cc_cipher_free(drvdata); - return rc; -} diff --git a/drivers/staging/ccree/cc_cipher.h b/drivers/staging/ccree/cc_cipher.h deleted file mode 100644 index 4c181c721723..000000000000 --- a/drivers/staging/ccree/cc_cipher.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -/* \file cc_cipher.h - * ARM CryptoCell Cipher Crypto API - */ - -#ifndef __CC_CIPHER_H__ -#define __CC_CIPHER_H__ - -#include <linux/kernel.h> -#include <crypto/algapi.h> -#include "cc_driver.h" -#include "cc_buffer_mgr.h" - -/* Crypto cipher flags */ -#define CC_CRYPTO_CIPHER_KEY_KFDE0 BIT(0) -#define CC_CRYPTO_CIPHER_KEY_KFDE1 BIT(1) -#define CC_CRYPTO_CIPHER_KEY_KFDE2 BIT(2) -#define CC_CRYPTO_CIPHER_KEY_KFDE3 BIT(3) -#define CC_CRYPTO_CIPHER_DU_SIZE_512B BIT(4) - -#define CC_CRYPTO_CIPHER_KEY_KFDE_MASK (CC_CRYPTO_CIPHER_KEY_KFDE0 | \ - CC_CRYPTO_CIPHER_KEY_KFDE1 | \ - CC_CRYPTO_CIPHER_KEY_KFDE2 | \ - CC_CRYPTO_CIPHER_KEY_KFDE3) - -struct blkcipher_req_ctx { - struct async_gen_req_ctx gen_ctx; - enum cc_req_dma_buf_type dma_buf_type; - u32 in_nents; - u32 in_mlli_nents; - u32 out_nents; - u32 out_mlli_nents; - u8 *backup_info; /*store iv for generated IV flow*/ - u8 *iv; - bool is_giv; - struct mlli_params mlli_params; -}; - -int cc_cipher_alloc(struct cc_drvdata *drvdata); - -int cc_cipher_free(struct cc_drvdata *drvdata); - -#ifndef CRYPTO_ALG_BULK_MASK - -#define CRYPTO_ALG_BULK_DU_512 0x00002000 -#define CRYPTO_ALG_BULK_DU_4096 0x00004000 -#define CRYPTO_ALG_BULK_MASK (CRYPTO_ALG_BULK_DU_512 |\ - CRYPTO_ALG_BULK_DU_4096) -#endif /* CRYPTO_ALG_BULK_MASK */ - -#ifdef CRYPTO_TFM_REQ_HW_KEY - -static inline bool cc_is_hw_key(struct crypto_tfm *tfm) -{ - return (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_HW_KEY); -} - -#else - -struct arm_hw_key_info { - int hw_key1; - int hw_key2; -}; - -static inline bool cc_is_hw_key(struct crypto_tfm *tfm) -{ - return false; -} - -#endif /* CRYPTO_TFM_REQ_HW_KEY */ - -#endif /*__CC_CIPHER_H__*/ diff --git a/drivers/staging/ccree/cc_crypto_ctx.h b/drivers/staging/ccree/cc_crypto_ctx.h deleted file mode 100644 index eb16842d7db9..000000000000 --- a/drivers/staging/ccree/cc_crypto_ctx.h +++ /dev/null @@ -1,170 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef _CC_CRYPTO_CTX_H_ -#define _CC_CRYPTO_CTX_H_ - -#include <linux/types.h> - -/* context size */ -#ifndef CC_CTX_SIZE_LOG2 -#if (CC_DEV_SHA_MAX > 256) -#define CC_CTX_SIZE_LOG2 8 -#else -#define CC_CTX_SIZE_LOG2 7 -#endif -#endif -#define CC_CTX_SIZE BIT(CC_CTX_SIZE_LOG2) -#define CC_DRV_CTX_SIZE_WORDS (CC_CTX_SIZE >> 2) - -#define CC_DRV_DES_IV_SIZE 8 -#define CC_DRV_DES_BLOCK_SIZE 8 - -#define CC_DRV_DES_ONE_KEY_SIZE 8 -#define CC_DRV_DES_DOUBLE_KEY_SIZE 16 -#define CC_DRV_DES_TRIPLE_KEY_SIZE 24 -#define CC_DRV_DES_KEY_SIZE_MAX CC_DRV_DES_TRIPLE_KEY_SIZE - -#define CC_AES_IV_SIZE 16 -#define CC_AES_IV_SIZE_WORDS (CC_AES_IV_SIZE >> 2) - -#define CC_AES_BLOCK_SIZE 16 -#define CC_AES_BLOCK_SIZE_WORDS 4 - -#define CC_AES_128_BIT_KEY_SIZE 16 -#define CC_AES_128_BIT_KEY_SIZE_WORDS (CC_AES_128_BIT_KEY_SIZE >> 2) -#define CC_AES_192_BIT_KEY_SIZE 24 -#define CC_AES_192_BIT_KEY_SIZE_WORDS (CC_AES_192_BIT_KEY_SIZE >> 2) -#define CC_AES_256_BIT_KEY_SIZE 32 -#define CC_AES_256_BIT_KEY_SIZE_WORDS (CC_AES_256_BIT_KEY_SIZE >> 2) -#define CC_AES_KEY_SIZE_MAX CC_AES_256_BIT_KEY_SIZE -#define CC_AES_KEY_SIZE_WORDS_MAX (CC_AES_KEY_SIZE_MAX >> 2) - -#define CC_MD5_DIGEST_SIZE 16 -#define CC_SHA1_DIGEST_SIZE 20 -#define CC_SHA224_DIGEST_SIZE 28 -#define CC_SHA256_DIGEST_SIZE 32 -#define CC_SHA256_DIGEST_SIZE_IN_WORDS 8 -#define CC_SHA384_DIGEST_SIZE 48 -#define CC_SHA512_DIGEST_SIZE 64 - -#define CC_SHA1_BLOCK_SIZE 64 -#define CC_SHA1_BLOCK_SIZE_IN_WORDS 16 -#define CC_MD5_BLOCK_SIZE 64 -#define CC_MD5_BLOCK_SIZE_IN_WORDS 16 -#define CC_SHA224_BLOCK_SIZE 64 -#define CC_SHA256_BLOCK_SIZE 64 -#define CC_SHA256_BLOCK_SIZE_IN_WORDS 16 -#define CC_SHA1_224_256_BLOCK_SIZE 64 -#define CC_SHA384_BLOCK_SIZE 128 -#define CC_SHA512_BLOCK_SIZE 128 - -#if (CC_DEV_SHA_MAX > 256) -#define CC_DIGEST_SIZE_MAX CC_SHA512_DIGEST_SIZE -#define CC_HASH_BLOCK_SIZE_MAX CC_SHA512_BLOCK_SIZE /*1024b*/ -#else /* Only up to SHA256 */ -#define CC_DIGEST_SIZE_MAX CC_SHA256_DIGEST_SIZE -#define CC_HASH_BLOCK_SIZE_MAX CC_SHA256_BLOCK_SIZE /*512b*/ -#endif - -#define CC_HMAC_BLOCK_SIZE_MAX CC_HASH_BLOCK_SIZE_MAX - -#define CC_DRV_ALG_MAX_BLOCK_SIZE CC_HASH_BLOCK_SIZE_MAX - -enum drv_engine_type { - DRV_ENGINE_NULL = 0, - DRV_ENGINE_AES = 1, - DRV_ENGINE_DES = 2, - DRV_ENGINE_HASH = 3, - DRV_ENGINE_RC4 = 4, - DRV_ENGINE_DOUT = 5, - DRV_ENGINE_RESERVE32B = S32_MAX, -}; - -enum drv_crypto_alg { - DRV_CRYPTO_ALG_NULL = -1, - DRV_CRYPTO_ALG_AES = 0, - DRV_CRYPTO_ALG_DES = 1, - DRV_CRYPTO_ALG_HASH = 2, - DRV_CRYPTO_ALG_C2 = 3, - DRV_CRYPTO_ALG_HMAC = 4, - DRV_CRYPTO_ALG_AEAD = 5, - DRV_CRYPTO_ALG_BYPASS = 6, - DRV_CRYPTO_ALG_NUM = 7, - DRV_CRYPTO_ALG_RESERVE32B = S32_MAX -}; - -enum drv_crypto_direction { - DRV_CRYPTO_DIRECTION_NULL = -1, - DRV_CRYPTO_DIRECTION_ENCRYPT = 0, - DRV_CRYPTO_DIRECTION_DECRYPT = 1, - DRV_CRYPTO_DIRECTION_DECRYPT_ENCRYPT = 3, - DRV_CRYPTO_DIRECTION_RESERVE32B = S32_MAX -}; - -enum drv_cipher_mode { - DRV_CIPHER_NULL_MODE = -1, - DRV_CIPHER_ECB = 0, - DRV_CIPHER_CBC = 1, - DRV_CIPHER_CTR = 2, - DRV_CIPHER_CBC_MAC = 3, - DRV_CIPHER_XTS = 4, - DRV_CIPHER_XCBC_MAC = 5, - DRV_CIPHER_OFB = 6, - DRV_CIPHER_CMAC = 7, - DRV_CIPHER_CCM = 8, - DRV_CIPHER_CBC_CTS = 11, - DRV_CIPHER_GCTR = 12, - DRV_CIPHER_ESSIV = 13, - DRV_CIPHER_BITLOCKER = 14, - DRV_CIPHER_RESERVE32B = S32_MAX -}; - -enum drv_hash_mode { - DRV_HASH_NULL = -1, - DRV_HASH_SHA1 = 0, - DRV_HASH_SHA256 = 1, - DRV_HASH_SHA224 = 2, - DRV_HASH_SHA512 = 3, - DRV_HASH_SHA384 = 4, - DRV_HASH_MD5 = 5, - DRV_HASH_CBC_MAC = 6, - DRV_HASH_XCBC_MAC = 7, - DRV_HASH_CMAC = 8, - DRV_HASH_MODE_NUM = 9, - DRV_HASH_RESERVE32B = S32_MAX -}; - -enum drv_hash_hw_mode { - DRV_HASH_HW_MD5 = 0, - DRV_HASH_HW_SHA1 = 1, - DRV_HASH_HW_SHA256 = 2, - DRV_HASH_HW_SHA224 = 10, - DRV_HASH_HW_SHA512 = 4, - DRV_HASH_HW_SHA384 = 12, - DRV_HASH_HW_GHASH = 6, - DRV_HASH_HW_RESERVE32B = S32_MAX -}; - -/* drv_crypto_key_type[1:0] is mapped to cipher_do[1:0] */ -/* drv_crypto_key_type[2] is mapped to cipher_config2 */ -enum drv_crypto_key_type { - DRV_NULL_KEY = -1, - DRV_USER_KEY = 0, /* 0x000 */ - DRV_ROOT_KEY = 1, /* 0x001 */ - DRV_PROVISIONING_KEY = 2, /* 0x010 */ - DRV_SESSION_KEY = 3, /* 0x011 */ - DRV_APPLET_KEY = 4, /* NA */ - DRV_PLATFORM_KEY = 5, /* 0x101 */ - DRV_CUSTOMER_KEY = 6, /* 0x110 */ - DRV_END_OF_KEYS = S32_MAX, -}; - -enum drv_crypto_padding_type { - DRV_PADDING_NONE = 0, - DRV_PADDING_PKCS7 = 1, - DRV_PADDING_RESERVE32B = S32_MAX -}; - -#endif /* _CC_CRYPTO_CTX_H_ */ - diff --git a/drivers/staging/ccree/cc_debugfs.c b/drivers/staging/ccree/cc_debugfs.c deleted file mode 100644 index 08f8db489cf0..000000000000 --- a/drivers/staging/ccree/cc_debugfs.c +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include <linux/debugfs.h> -#include <linux/stringify.h> -#include "cc_driver.h" -#include "cc_crypto_ctx.h" -#include "cc_debugfs.h" - -struct cc_debugfs_ctx { - struct dentry *dir; -}; - -#define CC_DEBUG_REG(_X) { \ - .name = __stringify(_X),\ - .offset = CC_REG(_X) \ - } - -/* - * This is a global var for the dentry of the - * debugfs ccree/ dir. It is not tied down to - * a specific instance of ccree, hence it is - * global. - */ -static struct dentry *cc_debugfs_dir; - -static struct debugfs_reg32 debug_regs[] = { - CC_DEBUG_REG(HOST_SIGNATURE), - CC_DEBUG_REG(HOST_IRR), - CC_DEBUG_REG(HOST_POWER_DOWN_EN), - CC_DEBUG_REG(AXIM_MON_ERR), - CC_DEBUG_REG(DSCRPTR_QUEUE_CONTENT), - CC_DEBUG_REG(HOST_IMR), - CC_DEBUG_REG(AXIM_CFG), - CC_DEBUG_REG(AXIM_CACHE_PARAMS), - CC_DEBUG_REG(HOST_VERSION), - CC_DEBUG_REG(GPR_HOST), - CC_DEBUG_REG(AXIM_MON_COMP), -}; - -int __init cc_debugfs_global_init(void) -{ - cc_debugfs_dir = debugfs_create_dir("ccree", NULL); - - return !cc_debugfs_dir; -} - -void __exit cc_debugfs_global_fini(void) -{ - debugfs_remove(cc_debugfs_dir); -} - -int cc_debugfs_init(struct cc_drvdata *drvdata) -{ - struct device *dev = drvdata_to_dev(drvdata); - struct cc_debugfs_ctx *ctx; - struct debugfs_regset32 *regset; - struct dentry *file; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL); - if (!regset) - return -ENOMEM; - - regset->regs = debug_regs; - regset->nregs = ARRAY_SIZE(debug_regs); - regset->base = drvdata->cc_base; - - ctx->dir = debugfs_create_dir(drvdata->plat_dev->name, cc_debugfs_dir); - if (!ctx->dir) - return -ENFILE; - - file = debugfs_create_regset32("regs", 0400, ctx->dir, regset); - if (!file) { - debugfs_remove(ctx->dir); - return -ENFILE; - } - - file = debugfs_create_bool("coherent", 0400, ctx->dir, - &drvdata->coherent); - - if (!file) { - debugfs_remove_recursive(ctx->dir); - return -ENFILE; - } - - drvdata->debugfs = ctx; - - return 0; -} - -void cc_debugfs_fini(struct cc_drvdata *drvdata) -{ - struct cc_debugfs_ctx *ctx = (struct cc_debugfs_ctx *)drvdata->debugfs; - - debugfs_remove_recursive(ctx->dir); -} diff --git a/drivers/staging/ccree/cc_debugfs.h b/drivers/staging/ccree/cc_debugfs.h deleted file mode 100644 index 5b5320eca7d2..000000000000 --- a/drivers/staging/ccree/cc_debugfs.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef __CC_DEBUGFS_H__ -#define __CC_DEBUGFS_H__ - -#ifdef CONFIG_DEBUG_FS -int cc_debugfs_global_init(void); -void cc_debugfs_global_fini(void); - -int cc_debugfs_init(struct cc_drvdata *drvdata); -void cc_debugfs_fini(struct cc_drvdata *drvdata); - -#else - -static inline int cc_debugfs_global_init(void) -{ - return 0; -} - -static inline void cc_debugfs_global_fini(void) {} - -static inline int cc_debugfs_init(struct cc_drvdata *drvdata) -{ - return 0; -} - -static inline void cc_debugfs_fini(struct cc_drvdata *drvdata) {} - -#endif - -#endif /*__CC_SYSFS_H__*/ diff --git a/drivers/staging/ccree/cc_driver.c b/drivers/staging/ccree/cc_driver.c deleted file mode 100644 index 3a1cb0c98648..000000000000 --- a/drivers/staging/ccree/cc_driver.c +++ /dev/null @@ -1,474 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include <linux/module.h> - -#include <linux/crypto.h> -#include <linux/moduleparam.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/of.h> -#include <linux/clk.h> -#include <linux/of_address.h> - -#include "cc_driver.h" -#include "cc_request_mgr.h" -#include "cc_buffer_mgr.h" -#include "cc_debugfs.h" -#include "cc_cipher.h" -#include "cc_aead.h" -#include "cc_hash.h" -#include "cc_ivgen.h" -#include "cc_sram_mgr.h" -#include "cc_pm.h" -#include "cc_fips.h" - -bool cc_dump_desc; -module_param_named(dump_desc, cc_dump_desc, bool, 0600); -MODULE_PARM_DESC(cc_dump_desc, "Dump descriptors to kernel log as debugging aid"); - -bool cc_dump_bytes; -module_param_named(dump_bytes, cc_dump_bytes, bool, 0600); -MODULE_PARM_DESC(cc_dump_bytes, "Dump buffers to kernel log as debugging aid"); - -void __dump_byte_array(const char *name, const u8 *buf, size_t len) -{ - char prefix[64]; - - if (!buf) - return; - - snprintf(prefix, sizeof(prefix), "%s[%zu]: ", name, len); - - print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_ADDRESS, 16, 1, buf, - len, false); -} - -static irqreturn_t cc_isr(int irq, void *dev_id) -{ - struct cc_drvdata *drvdata = (struct cc_drvdata *)dev_id; - struct device *dev = drvdata_to_dev(drvdata); - u32 irr; - u32 imr; - - /* STAT_OP_TYPE_GENERIC STAT_PHASE_0: Interrupt */ - - /* read the interrupt status */ - irr = cc_ioread(drvdata, CC_REG(HOST_IRR)); - dev_dbg(dev, "Got IRR=0x%08X\n", irr); - if (irr == 0) { /* Probably shared interrupt line */ - dev_err(dev, "Got interrupt with empty IRR\n"); - return IRQ_NONE; - } - imr = cc_ioread(drvdata, CC_REG(HOST_IMR)); - - /* clear interrupt - must be before processing events */ - cc_iowrite(drvdata, CC_REG(HOST_ICR), irr); - - drvdata->irq = irr; - /* Completion interrupt - most probable */ - if (irr & CC_COMP_IRQ_MASK) { - /* Mask AXI completion interrupt - will be unmasked in - * Deferred service handler - */ - cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | CC_COMP_IRQ_MASK); - irr &= ~CC_COMP_IRQ_MASK; - complete_request(drvdata); - } -#ifdef CONFIG_CRYPTO_FIPS - /* TEE FIPS interrupt */ - if (irr & CC_GPR0_IRQ_MASK) { - /* Mask interrupt - will be unmasked in Deferred service - * handler - */ - cc_iowrite(drvdata, CC_REG(HOST_IMR), imr | CC_GPR0_IRQ_MASK); - irr &= ~CC_GPR0_IRQ_MASK; - fips_handler(drvdata); - } -#endif - /* AXI error interrupt */ - if (irr & CC_AXI_ERR_IRQ_MASK) { - u32 axi_err; - - /* Read the AXI error ID */ - axi_err = cc_ioread(drvdata, CC_REG(AXIM_MON_ERR)); - dev_dbg(dev, "AXI completion error: axim_mon_err=0x%08X\n", - axi_err); - - irr &= ~CC_AXI_ERR_IRQ_MASK; - } - - if (irr) { - dev_dbg(dev, "IRR includes unknown cause bits (0x%08X)\n", - irr); - /* Just warning */ - } - - return IRQ_HANDLED; -} - -int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe) -{ - unsigned int val, cache_params; - struct device *dev = drvdata_to_dev(drvdata); - - /* Unmask all AXI interrupt sources AXI_CFG1 register */ - val = cc_ioread(drvdata, CC_REG(AXIM_CFG)); - cc_iowrite(drvdata, CC_REG(AXIM_CFG), val & ~CC_AXI_IRQ_MASK); - dev_dbg(dev, "AXIM_CFG=0x%08X\n", - cc_ioread(drvdata, CC_REG(AXIM_CFG))); - - /* Clear all pending interrupts */ - val = cc_ioread(drvdata, CC_REG(HOST_IRR)); - dev_dbg(dev, "IRR=0x%08X\n", val); - cc_iowrite(drvdata, CC_REG(HOST_ICR), val); - - /* Unmask relevant interrupt cause */ - val = (unsigned int)(~(CC_COMP_IRQ_MASK | CC_AXI_ERR_IRQ_MASK | - CC_GPR0_IRQ_MASK)); - cc_iowrite(drvdata, CC_REG(HOST_IMR), val); - - cache_params = (drvdata->coherent ? CC_COHERENT_CACHE_PARAMS : 0x0); - - val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS)); - - if (is_probe) - dev_info(dev, "Cache params previous: 0x%08X\n", val); - - cc_iowrite(drvdata, CC_REG(AXIM_CACHE_PARAMS), cache_params); - val = cc_ioread(drvdata, CC_REG(AXIM_CACHE_PARAMS)); - - if (is_probe) - dev_info(dev, "Cache params current: 0x%08X (expect: 0x%08X)\n", - val, cache_params); - - return 0; -} - -static int init_cc_resources(struct platform_device *plat_dev) -{ - struct resource *req_mem_cc_regs = NULL; - struct cc_drvdata *new_drvdata; - struct device *dev = &plat_dev->dev; - struct device_node *np = dev->of_node; - u32 signature_val; - u64 dma_mask; - int rc = 0; - - new_drvdata = devm_kzalloc(dev, sizeof(*new_drvdata), GFP_KERNEL); - if (!new_drvdata) - return -ENOMEM; - - platform_set_drvdata(plat_dev, new_drvdata); - new_drvdata->plat_dev = plat_dev; - - new_drvdata->clk = of_clk_get(np, 0); - new_drvdata->coherent = of_dma_is_coherent(np); - - /* Get device resources */ - /* First CC registers space */ - req_mem_cc_regs = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); - /* Map registers space */ - new_drvdata->cc_base = devm_ioremap_resource(dev, req_mem_cc_regs); - if (IS_ERR(new_drvdata->cc_base)) - return PTR_ERR(new_drvdata->cc_base); - - dev_dbg(dev, "Got MEM resource (%s): %pR\n", req_mem_cc_regs->name, - req_mem_cc_regs); - dev_dbg(dev, "CC registers mapped from %pa to 0x%p\n", - &req_mem_cc_regs->start, new_drvdata->cc_base); - - /* Then IRQ */ - new_drvdata->irq = platform_get_irq(plat_dev, 0); - if (new_drvdata->irq < 0) { - dev_err(dev, "Failed getting IRQ resource\n"); - return new_drvdata->irq; - } - - rc = devm_request_irq(dev, new_drvdata->irq, cc_isr, - IRQF_SHARED, "arm_cc7x", new_drvdata); - if (rc) { - dev_err(dev, "Could not register to interrupt %d\n", - new_drvdata->irq); - return rc; - } - dev_dbg(dev, "Registered to IRQ: %d\n", new_drvdata->irq); - - init_completion(&new_drvdata->hw_queue_avail); - - if (!plat_dev->dev.dma_mask) - plat_dev->dev.dma_mask = &plat_dev->dev.coherent_dma_mask; - - dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN); - while (dma_mask > 0x7fffffffUL) { - if (dma_supported(&plat_dev->dev, dma_mask)) { - rc = dma_set_coherent_mask(&plat_dev->dev, dma_mask); - if (!rc) - break; - } - dma_mask >>= 1; - } - - if (rc) { - dev_err(dev, "Failed in dma_set_mask, mask=%par\n", &dma_mask); - return rc; - } - - rc = cc_clk_on(new_drvdata); - if (rc) { - dev_err(dev, "Failed to enable clock"); - return rc; - } - - /* Verify correct mapping */ - signature_val = cc_ioread(new_drvdata, CC_REG(HOST_SIGNATURE)); - if (signature_val != CC_DEV_SIGNATURE) { - dev_err(dev, "Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n", - signature_val, (u32)CC_DEV_SIGNATURE); - rc = -EINVAL; - goto post_clk_err; - } - dev_dbg(dev, "CC SIGNATURE=0x%08X\n", signature_val); - - /* Display HW versions */ - dev_info(dev, "ARM CryptoCell %s Driver: HW version 0x%08X, Driver version %s\n", - CC_DEV_NAME_STR, - cc_ioread(new_drvdata, CC_REG(HOST_VERSION)), - DRV_MODULE_VERSION); - - rc = init_cc_regs(new_drvdata, true); - if (rc) { - dev_err(dev, "init_cc_regs failed\n"); - goto post_clk_err; - } - - rc = cc_debugfs_init(new_drvdata); - if (rc) { - dev_err(dev, "Failed registering debugfs interface\n"); - goto post_regs_err; - } - - rc = cc_fips_init(new_drvdata); - if (rc) { - dev_err(dev, "CC_FIPS_INIT failed 0x%x\n", rc); - goto post_debugfs_err; - } - rc = cc_sram_mgr_init(new_drvdata); - if (rc) { - dev_err(dev, "cc_sram_mgr_init failed\n"); - goto post_fips_init_err; - } - - new_drvdata->mlli_sram_addr = - cc_sram_alloc(new_drvdata, MAX_MLLI_BUFF_SIZE); - if (new_drvdata->mlli_sram_addr == NULL_SRAM_ADDR) { - dev_err(dev, "Failed to alloc MLLI Sram buffer\n"); - rc = -ENOMEM; - goto post_sram_mgr_err; - } - - rc = cc_req_mgr_init(new_drvdata); - if (rc) { - dev_err(dev, "cc_req_mgr_init failed\n"); - goto post_sram_mgr_err; - } - - rc = cc_buffer_mgr_init(new_drvdata); - if (rc) { - dev_err(dev, "buffer_mgr_init failed\n"); - goto post_req_mgr_err; - } - - rc = cc_pm_init(new_drvdata); - if (rc) { - dev_err(dev, "ssi_power_mgr_init failed\n"); - goto post_buf_mgr_err; - } - - rc = cc_ivgen_init(new_drvdata); - if (rc) { - dev_err(dev, "cc_ivgen_init failed\n"); - goto post_power_mgr_err; - } - - /* Allocate crypto algs */ - rc = cc_cipher_alloc(new_drvdata); - if (rc) { - dev_err(dev, "cc_cipher_alloc failed\n"); - goto post_ivgen_err; - } - - /* hash must be allocated before aead since hash exports APIs */ - rc = cc_hash_alloc(new_drvdata); - if (rc) { - dev_err(dev, "cc_hash_alloc failed\n"); - goto post_cipher_err; - } - - rc = cc_aead_alloc(new_drvdata); - if (rc) { - dev_err(dev, "cc_aead_alloc failed\n"); - goto post_hash_err; - } - - /* If we got here and FIPS mode is enabled - * it means all FIPS test passed, so let TEE - * know we're good. - */ - cc_set_ree_fips_status(new_drvdata, true); - - return 0; - -post_hash_err: - cc_hash_free(new_drvdata); -post_cipher_err: - cc_cipher_free(new_drvdata); -post_ivgen_err: - cc_ivgen_fini(new_drvdata); -post_power_mgr_err: - cc_pm_fini(new_drvdata); -post_buf_mgr_err: - cc_buffer_mgr_fini(new_drvdata); -post_req_mgr_err: - cc_req_mgr_fini(new_drvdata); -post_sram_mgr_err: - cc_sram_mgr_fini(new_drvdata); -post_fips_init_err: - cc_fips_fini(new_drvdata); -post_debugfs_err: - cc_debugfs_fini(new_drvdata); -post_regs_err: - fini_cc_regs(new_drvdata); -post_clk_err: - cc_clk_off(new_drvdata); - return rc; -} - -void fini_cc_regs(struct cc_drvdata *drvdata) -{ - /* Mask all interrupts */ - cc_iowrite(drvdata, CC_REG(HOST_IMR), 0xFFFFFFFF); -} - -static void cleanup_cc_resources(struct platform_device *plat_dev) -{ - struct cc_drvdata *drvdata = - (struct cc_drvdata *)platform_get_drvdata(plat_dev); - - cc_aead_free(drvdata); - cc_hash_free(drvdata); - cc_cipher_free(drvdata); - cc_ivgen_fini(drvdata); - cc_pm_fini(drvdata); - cc_buffer_mgr_fini(drvdata); - cc_req_mgr_fini(drvdata); - cc_sram_mgr_fini(drvdata); - cc_fips_fini(drvdata); - cc_debugfs_fini(drvdata); - fini_cc_regs(drvdata); - cc_clk_off(drvdata); -} - -int cc_clk_on(struct cc_drvdata *drvdata) -{ - struct clk *clk = drvdata->clk; - int rc; - - if (IS_ERR(clk)) - /* Not all devices have a clock associated with CCREE */ - return 0; - - rc = clk_prepare_enable(clk); - if (rc) - return rc; - - return 0; -} - -void cc_clk_off(struct cc_drvdata *drvdata) -{ - struct clk *clk = drvdata->clk; - - if (IS_ERR(clk)) - /* Not all devices have a clock associated with CCREE */ - return; - - clk_disable_unprepare(clk); -} - -static int cc7x_probe(struct platform_device *plat_dev) -{ - int rc; - struct device *dev = &plat_dev->dev; - - /* Map registers space */ - rc = init_cc_resources(plat_dev); - if (rc) - return rc; - - dev_info(dev, "ARM ccree device initialized\n"); - - return 0; -} - -static int cc7x_remove(struct platform_device *plat_dev) -{ - struct device *dev = &plat_dev->dev; - - dev_dbg(dev, "Releasing cc7x resources...\n"); - - cleanup_cc_resources(plat_dev); - - dev_info(dev, "ARM ccree device terminated\n"); - - return 0; -} - -static const struct of_device_id arm_cc7x_dev_of_match[] = { - {.compatible = "arm,cryptocell-712-ree"}, - {} -}; -MODULE_DEVICE_TABLE(of, arm_cc7x_dev_of_match); - -static struct platform_driver cc7x_driver = { - .driver = { - .name = "cc7xree", - .of_match_table = arm_cc7x_dev_of_match, -#ifdef CONFIG_PM - .pm = &ccree_pm, -#endif - }, - .probe = cc7x_probe, - .remove = cc7x_remove, -}; - -static int __init ccree_init(void) -{ - int ret; - - cc_hash_global_init(); - - ret = cc_debugfs_global_init(); - if (ret) - return ret; - - return platform_driver_register(&cc7x_driver); -} -module_init(ccree_init); - -static void __exit ccree_exit(void) -{ - platform_driver_unregister(&cc7x_driver); - cc_debugfs_global_fini(); -} -module_exit(ccree_exit); - -/* Module description */ -MODULE_DESCRIPTION("ARM TrustZone CryptoCell REE Driver"); -MODULE_VERSION(DRV_MODULE_VERSION); -MODULE_AUTHOR("ARM"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/ccree/cc_driver.h b/drivers/staging/ccree/cc_driver.h deleted file mode 100644 index 773ac591c45c..000000000000 --- a/drivers/staging/ccree/cc_driver.h +++ /dev/null @@ -1,194 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -/* \file cc_driver.h - * ARM CryptoCell Linux Crypto Driver - */ - -#ifndef __CC_DRIVER_H__ -#define __CC_DRIVER_H__ - -#ifdef COMP_IN_WQ -#include <linux/workqueue.h> -#else -#include <linux/interrupt.h> -#endif -#include <linux/dma-mapping.h> -#include <crypto/algapi.h> -#include <crypto/internal/skcipher.h> -#include <crypto/aes.h> -#include <crypto/sha.h> -#include <crypto/aead.h> -#include <crypto/authenc.h> -#include <crypto/hash.h> -#include <linux/version.h> -#include <linux/clk.h> -#include <linux/platform_device.h> - -/* Registers definitions from shared/hw/ree_include */ -#include "cc_host_regs.h" -#define CC_DEV_SHA_MAX 512 -#include "cc_crypto_ctx.h" -#include "cc_hw_queue_defs.h" -#include "cc_sram_mgr.h" - -extern bool cc_dump_desc; -extern bool cc_dump_bytes; - -#define DRV_MODULE_VERSION "3.0" - -#define CC_DEV_NAME_STR "cc715ree" -#define CC_COHERENT_CACHE_PARAMS 0xEEE - -/* Maximum DMA mask supported by IP */ -#define DMA_BIT_MASK_LEN 48 - -#define CC_DEV_SIGNATURE 0xDCC71200UL - -#define CC_AXI_IRQ_MASK ((1 << CC_AXIM_CFG_BRESPMASK_BIT_SHIFT) | \ - (1 << CC_AXIM_CFG_RRESPMASK_BIT_SHIFT) | \ - (1 << CC_AXIM_CFG_INFLTMASK_BIT_SHIFT) | \ - (1 << CC_AXIM_CFG_COMPMASK_BIT_SHIFT)) - -#define CC_AXI_ERR_IRQ_MASK BIT(CC_HOST_IRR_AXI_ERR_INT_BIT_SHIFT) - -#define CC_COMP_IRQ_MASK BIT(CC_HOST_IRR_AXIM_COMP_INT_BIT_SHIFT) - -#define AXIM_MON_COMP_VALUE GENMASK(CC_AXIM_MON_COMP_VALUE_BIT_SIZE + \ - CC_AXIM_MON_COMP_VALUE_BIT_SHIFT, \ - CC_AXIM_MON_COMP_VALUE_BIT_SHIFT) - -/* Register name mangling macro */ -#define CC_REG(reg_name) CC_ ## reg_name ## _REG_OFFSET - -/* TEE FIPS status interrupt */ -#define CC_GPR0_IRQ_MASK BIT(CC_HOST_IRR_GPR0_BIT_SHIFT) - -#define CC_CRA_PRIO 3000 - -#define MIN_HW_QUEUE_SIZE 50 /* Minimum size required for proper function */ - -#define MAX_REQUEST_QUEUE_SIZE 4096 -#define MAX_MLLI_BUFF_SIZE 2080 -#define MAX_ICV_NENTS_SUPPORTED 2 - -/* Definitions for HW descriptors DIN/DOUT fields */ -#define NS_BIT 1 -#define AXI_ID 0 -/* AXI_ID is not actually the AXI ID of the transaction but the value of AXI_ID - * field in the HW descriptor. The DMA engine +8 that value. - */ - -#define CC_MAX_IVGEN_DMA_ADDRESSES 3 -struct cc_crypto_req { - void (*user_cb)(struct device *dev, void *req, int err); - void *user_arg; - dma_addr_t ivgen_dma_addr[CC_MAX_IVGEN_DMA_ADDRESSES]; - /* For the first 'ivgen_dma_addr_len' addresses of this array, - * generated IV would be placed in it by send_request(). - * Same generated IV for all addresses! - */ - /* Amount of 'ivgen_dma_addr' elements to be filled. */ - unsigned int ivgen_dma_addr_len; - /* The generated IV size required, 8/16 B allowed. */ - unsigned int ivgen_size; - struct completion seq_compl; /* request completion */ -}; - -/** - * struct cc_drvdata - driver private data context - * @cc_base: virt address of the CC registers - * @irq: device IRQ number - * @irq_mask: Interrupt mask shadow (1 for masked interrupts) - * @fw_ver: SeP loaded firmware version - */ -struct cc_drvdata { - void __iomem *cc_base; - int irq; - u32 irq_mask; - u32 fw_ver; - struct completion hw_queue_avail; /* wait for HW queue availability */ - struct platform_device *plat_dev; - cc_sram_addr_t mlli_sram_addr; - void *buff_mgr_handle; - void *hash_handle; - void *aead_handle; - void *blkcipher_handle; - void *request_mgr_handle; - void *fips_handle; - void *ivgen_handle; - void *sram_mgr_handle; - void *debugfs; - struct clk *clk; - bool coherent; -}; - -struct cc_crypto_alg { - struct list_head entry; - int cipher_mode; - int flow_mode; /* Note: currently, refers to the cipher mode only. */ - int auth_mode; - struct cc_drvdata *drvdata; - struct crypto_alg crypto_alg; - struct aead_alg aead_alg; -}; - -struct cc_alg_template { - char name[CRYPTO_MAX_ALG_NAME]; - char driver_name[CRYPTO_MAX_ALG_NAME]; - unsigned int blocksize; - u32 type; - union { - struct ablkcipher_alg ablkcipher; - struct aead_alg aead; - struct blkcipher_alg blkcipher; - struct cipher_alg cipher; - struct compress_alg compress; - } template_u; - int cipher_mode; - int flow_mode; /* Note: currently, refers to the cipher mode only. */ - int auth_mode; - struct cc_drvdata *drvdata; -}; - -struct async_gen_req_ctx { - dma_addr_t iv_dma_addr; - enum drv_crypto_direction op_type; -}; - -static inline struct device *drvdata_to_dev(struct cc_drvdata *drvdata) -{ - return &drvdata->plat_dev->dev; -} - -void __dump_byte_array(const char *name, const u8 *buf, size_t len); -static inline void dump_byte_array(const char *name, const u8 *the_array, - size_t size) -{ - if (cc_dump_bytes) - __dump_byte_array(name, the_array, size); -} - -int init_cc_regs(struct cc_drvdata *drvdata, bool is_probe); -void fini_cc_regs(struct cc_drvdata *drvdata); -int cc_clk_on(struct cc_drvdata *drvdata); -void cc_clk_off(struct cc_drvdata *drvdata); - -static inline void cc_iowrite(struct cc_drvdata *drvdata, u32 reg, u32 val) -{ - iowrite32(val, (drvdata->cc_base + reg)); -} - -static inline u32 cc_ioread(struct cc_drvdata *drvdata, u32 reg) -{ - return ioread32(drvdata->cc_base + reg); -} - -static inline gfp_t cc_gfp_flags(struct crypto_async_request *req) -{ - return (req->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC; -} - -#endif /*__CC_DRIVER_H__*/ - diff --git a/drivers/staging/ccree/cc_fips.c b/drivers/staging/ccree/cc_fips.c deleted file mode 100644 index de08af976b7f..000000000000 --- a/drivers/staging/ccree/cc_fips.c +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include <linux/fips.h> - -#include "cc_driver.h" -#include "cc_fips.h" - -static void fips_dsr(unsigned long devarg); - -struct cc_fips_handle { - struct tasklet_struct tasklet; -}; - -/* The function called once at driver entry point to check - * whether TEE FIPS error occurred. - */ -static bool cc_get_tee_fips_status(struct cc_drvdata *drvdata) -{ - u32 reg; - - reg = cc_ioread(drvdata, CC_REG(GPR_HOST)); - return (reg == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)); -} - -/* - * This function should push the FIPS REE library status towards the TEE library - * by writing the error state to HOST_GPR0 register. - */ -void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool status) -{ - int val = CC_FIPS_SYNC_REE_STATUS; - - val |= (status ? CC_FIPS_SYNC_MODULE_OK : CC_FIPS_SYNC_MODULE_ERROR); - - cc_iowrite(drvdata, CC_REG(HOST_GPR0), val); -} - -void cc_fips_fini(struct cc_drvdata *drvdata) -{ - struct cc_fips_handle *fips_h = drvdata->fips_handle; - - if (!fips_h) - return; /* Not allocated */ - - /* Kill tasklet */ - tasklet_kill(&fips_h->tasklet); - - kfree(fips_h); - drvdata->fips_handle = NULL; -} - -void fips_handler(struct cc_drvdata *drvdata) -{ - struct cc_fips_handle *fips_handle_ptr = drvdata->fips_handle; - - tasklet_schedule(&fips_handle_ptr->tasklet); -} - -static inline void tee_fips_error(struct device *dev) -{ - if (fips_enabled) - panic("ccree: TEE reported cryptographic error in fips mode!\n"); - else - dev_err(dev, "TEE reported error!\n"); -} - -/* Deferred service handler, run as interrupt-fired tasklet */ -static void fips_dsr(unsigned long devarg) -{ - struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg; - struct device *dev = drvdata_to_dev(drvdata); - u32 irq, state, val; - - irq = (drvdata->irq & (CC_GPR0_IRQ_MASK)); - - if (irq) { - state = cc_ioread(drvdata, CC_REG(GPR_HOST)); - - if (state != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) - tee_fips_error(dev); - } - - /* after verifing that there is nothing to do, - * unmask AXI completion interrupt. - */ - val = (CC_REG(HOST_IMR) & ~irq); - cc_iowrite(drvdata, CC_REG(HOST_IMR), val); -} - -/* The function called once at driver entry point .*/ -int cc_fips_init(struct cc_drvdata *p_drvdata) -{ - struct cc_fips_handle *fips_h; - struct device *dev = drvdata_to_dev(p_drvdata); - - fips_h = kzalloc(sizeof(*fips_h), GFP_KERNEL); - if (!fips_h) - return -ENOMEM; - - p_drvdata->fips_handle = fips_h; - - dev_dbg(dev, "Initializing fips tasklet\n"); - tasklet_init(&fips_h->tasklet, fips_dsr, (unsigned long)p_drvdata); - - if (!cc_get_tee_fips_status(p_drvdata)) - tee_fips_error(dev); - - return 0; -} diff --git a/drivers/staging/ccree/cc_fips.h b/drivers/staging/ccree/cc_fips.h deleted file mode 100644 index 0d520030095b..000000000000 --- a/drivers/staging/ccree/cc_fips.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef __CC_FIPS_H__ -#define __CC_FIPS_H__ - -#ifdef CONFIG_CRYPTO_FIPS - -enum cc_fips_status { - CC_FIPS_SYNC_MODULE_OK = 0x0, - CC_FIPS_SYNC_MODULE_ERROR = 0x1, - CC_FIPS_SYNC_REE_STATUS = 0x4, - CC_FIPS_SYNC_TEE_STATUS = 0x8, - CC_FIPS_SYNC_STATUS_RESERVE32B = S32_MAX -}; - -int cc_fips_init(struct cc_drvdata *p_drvdata); -void cc_fips_fini(struct cc_drvdata *drvdata); -void fips_handler(struct cc_drvdata *drvdata); -void cc_set_ree_fips_status(struct cc_drvdata *drvdata, bool ok); - -#else /* CONFIG_CRYPTO_FIPS */ - -static inline int cc_fips_init(struct cc_drvdata *p_drvdata) -{ - return 0; -} - -static inline void cc_fips_fini(struct cc_drvdata *drvdata) {} -static inline void cc_set_ree_fips_status(struct cc_drvdata *drvdata, - bool ok) {} -static inline void fips_handler(struct cc_drvdata *drvdata) {} - -#endif /* CONFIG_CRYPTO_FIPS */ - -#endif /*__CC_FIPS_H__*/ - diff --git a/drivers/staging/ccree/cc_hash.c b/drivers/staging/ccree/cc_hash.c deleted file mode 100644 index 8afc39f10bb3..000000000000 --- a/drivers/staging/ccree/cc_hash.c +++ /dev/null @@ -1,2295 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <crypto/algapi.h> -#include <crypto/hash.h> -#include <crypto/md5.h> -#include <crypto/internal/hash.h> - -#include "cc_driver.h" -#include "cc_request_mgr.h" -#include "cc_buffer_mgr.h" -#include "cc_hash.h" -#include "cc_sram_mgr.h" - -#define CC_MAX_HASH_SEQ_LEN 12 -#define CC_MAX_OPAD_KEYS_SIZE CC_MAX_HASH_BLCK_SIZE - -struct cc_hash_handle { - cc_sram_addr_t digest_len_sram_addr; /* const value in SRAM*/ - cc_sram_addr_t larval_digest_sram_addr; /* const value in SRAM */ - struct list_head hash_list; -}; - -static const u32 digest_len_init[] = { - 0x00000040, 0x00000000, 0x00000000, 0x00000000 }; -static const u32 md5_init[] = { - SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 }; -static const u32 sha1_init[] = { - SHA1_H4, SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 }; -static const u32 sha224_init[] = { - SHA224_H7, SHA224_H6, SHA224_H5, SHA224_H4, - SHA224_H3, SHA224_H2, SHA224_H1, SHA224_H0 }; -static const u32 sha256_init[] = { - SHA256_H7, SHA256_H6, SHA256_H5, SHA256_H4, - SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 }; -#if (CC_DEV_SHA_MAX > 256) -static const u32 digest_len_sha512_init[] = { - 0x00000080, 0x00000000, 0x00000000, 0x00000000 }; -static u64 sha384_init[] = { - SHA384_H7, SHA384_H6, SHA384_H5, SHA384_H4, - SHA384_H3, SHA384_H2, SHA384_H1, SHA384_H0 }; -static u64 sha512_init[] = { - SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4, - SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 }; -#endif - -static void cc_setup_xcbc(struct ahash_request *areq, struct cc_hw_desc desc[], - unsigned int *seq_size); - -static void cc_setup_cmac(struct ahash_request *areq, struct cc_hw_desc desc[], - unsigned int *seq_size); - -static const void *cc_larval_digest(struct device *dev, u32 mode); - -struct cc_hash_alg { - struct list_head entry; - int hash_mode; - int hw_mode; - int inter_digestsize; - struct cc_drvdata *drvdata; - struct ahash_alg ahash_alg; -}; - -struct hash_key_req_ctx { - u32 keylen; - dma_addr_t key_dma_addr; -}; - -/* hash per-session context */ -struct cc_hash_ctx { - struct cc_drvdata *drvdata; - /* holds the origin digest; the digest after "setkey" if HMAC,* - * the initial digest if HASH. - */ - u8 digest_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned; - u8 opad_tmp_keys_buff[CC_MAX_OPAD_KEYS_SIZE] ____cacheline_aligned; - - dma_addr_t opad_tmp_keys_dma_addr ____cacheline_aligned; - dma_addr_t digest_buff_dma_addr; - /* use for hmac with key large then mode block size */ - struct hash_key_req_ctx key_params; - int hash_mode; - int hw_mode; - int inter_digestsize; - struct completion setkey_comp; - bool is_hmac; -}; - -static void cc_set_desc(struct ahash_req_ctx *areq_ctx, struct cc_hash_ctx *ctx, - unsigned int flow_mode, struct cc_hw_desc desc[], - bool is_not_last_data, unsigned int *seq_size); - -static void cc_set_endianity(u32 mode, struct cc_hw_desc *desc) -{ - if (mode == DRV_HASH_MD5 || mode == DRV_HASH_SHA384 || - mode == DRV_HASH_SHA512) { - set_bytes_swap(desc, 1); - } else { - set_cipher_config0(desc, HASH_DIGEST_RESULT_LITTLE_ENDIAN); - } -} - -static int cc_map_result(struct device *dev, struct ahash_req_ctx *state, - unsigned int digestsize) -{ - state->digest_result_dma_addr = - dma_map_single(dev, state->digest_result_buff, - digestsize, DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, state->digest_result_dma_addr)) { - dev_err(dev, "Mapping digest result buffer %u B for DMA failed\n", - digestsize); - return -ENOMEM; - } - dev_dbg(dev, "Mapped digest result buffer %u B at va=%pK to dma=%pad\n", - digestsize, state->digest_result_buff, - &state->digest_result_dma_addr); - - return 0; -} - -static void cc_init_req(struct device *dev, struct ahash_req_ctx *state, - struct cc_hash_ctx *ctx) -{ - bool is_hmac = ctx->is_hmac; - - memset(state, 0, sizeof(*state)); - - if (is_hmac) { - if (ctx->hw_mode != DRV_CIPHER_XCBC_MAC && - ctx->hw_mode != DRV_CIPHER_CMAC) { - dma_sync_single_for_cpu(dev, ctx->digest_buff_dma_addr, - ctx->inter_digestsize, - DMA_BIDIRECTIONAL); - - memcpy(state->digest_buff, ctx->digest_buff, - ctx->inter_digestsize); -#if (CC_DEV_SHA_MAX > 256) - if (ctx->hash_mode == DRV_HASH_SHA512 || - ctx->hash_mode == DRV_HASH_SHA384) - memcpy(state->digest_bytes_len, - digest_len_sha512_init, HASH_LEN_SIZE); - else - memcpy(state->digest_bytes_len, - digest_len_init, HASH_LEN_SIZE); -#else - memcpy(state->digest_bytes_len, digest_len_init, - HASH_LEN_SIZE); -#endif - } - - if (ctx->hash_mode != DRV_HASH_NULL) { - dma_sync_single_for_cpu(dev, - ctx->opad_tmp_keys_dma_addr, - ctx->inter_digestsize, - DMA_BIDIRECTIONAL); - memcpy(state->opad_digest_buff, - ctx->opad_tmp_keys_buff, ctx->inter_digestsize); - } - } else { /*hash*/ - /* Copy the initial digests if hash flow. */ - const void *larval = cc_larval_digest(dev, ctx->hash_mode); - - memcpy(state->digest_buff, larval, ctx->inter_digestsize); - } -} - -static int cc_map_req(struct device *dev, struct ahash_req_ctx *state, - struct cc_hash_ctx *ctx) -{ - bool is_hmac = ctx->is_hmac; - - state->digest_buff_dma_addr = - dma_map_single(dev, state->digest_buff, - ctx->inter_digestsize, DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, state->digest_buff_dma_addr)) { - dev_err(dev, "Mapping digest len %d B at va=%pK for DMA failed\n", - ctx->inter_digestsize, state->digest_buff); - return -EINVAL; - } - dev_dbg(dev, "Mapped digest %d B at va=%pK to dma=%pad\n", - ctx->inter_digestsize, state->digest_buff, - &state->digest_buff_dma_addr); - - if (ctx->hw_mode != DRV_CIPHER_XCBC_MAC) { - state->digest_bytes_len_dma_addr = - dma_map_single(dev, state->digest_bytes_len, - HASH_LEN_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, state->digest_bytes_len_dma_addr)) { - dev_err(dev, "Mapping digest len %u B at va=%pK for DMA failed\n", - HASH_LEN_SIZE, state->digest_bytes_len); - goto unmap_digest_buf; - } - dev_dbg(dev, "Mapped digest len %u B at va=%pK to dma=%pad\n", - HASH_LEN_SIZE, state->digest_bytes_len, - &state->digest_bytes_len_dma_addr); - } - - if (is_hmac && ctx->hash_mode != DRV_HASH_NULL) { - state->opad_digest_dma_addr = - dma_map_single(dev, state->opad_digest_buff, - ctx->inter_digestsize, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, state->opad_digest_dma_addr)) { - dev_err(dev, "Mapping opad digest %d B at va=%pK for DMA failed\n", - ctx->inter_digestsize, - state->opad_digest_buff); - goto unmap_digest_len; - } - dev_dbg(dev, "Mapped opad digest %d B at va=%pK to dma=%pad\n", - ctx->inter_digestsize, state->opad_digest_buff, - &state->opad_digest_dma_addr); - } - - return 0; - -unmap_digest_len: - if (state->digest_bytes_len_dma_addr) { - dma_unmap_single(dev, state->digest_bytes_len_dma_addr, - HASH_LEN_SIZE, DMA_BIDIRECTIONAL); - state->digest_bytes_len_dma_addr = 0; - } -unmap_digest_buf: - if (state->digest_buff_dma_addr) { - dma_unmap_single(dev, state->digest_buff_dma_addr, - ctx->inter_digestsize, DMA_BIDIRECTIONAL); - state->digest_buff_dma_addr = 0; - } - - return -EINVAL; -} - -static void cc_unmap_req(struct device *dev, struct ahash_req_ctx *state, - struct cc_hash_ctx *ctx) -{ - if (state->digest_buff_dma_addr) { - dma_unmap_single(dev, state->digest_buff_dma_addr, - ctx->inter_digestsize, DMA_BIDIRECTIONAL); - dev_dbg(dev, "Unmapped digest-buffer: digest_buff_dma_addr=%pad\n", - &state->digest_buff_dma_addr); - state->digest_buff_dma_addr = 0; - } - if (state->digest_bytes_len_dma_addr) { - dma_unmap_single(dev, state->digest_bytes_len_dma_addr, - HASH_LEN_SIZE, DMA_BIDIRECTIONAL); - dev_dbg(dev, "Unmapped digest-bytes-len buffer: digest_bytes_len_dma_addr=%pad\n", - &state->digest_bytes_len_dma_addr); - state->digest_bytes_len_dma_addr = 0; - } - if (state->opad_digest_dma_addr) { - dma_unmap_single(dev, state->opad_digest_dma_addr, - ctx->inter_digestsize, DMA_BIDIRECTIONAL); - dev_dbg(dev, "Unmapped opad-digest: opad_digest_dma_addr=%pad\n", - &state->opad_digest_dma_addr); - state->opad_digest_dma_addr = 0; - } -} - -static void cc_unmap_result(struct device *dev, struct ahash_req_ctx *state, - unsigned int digestsize, u8 *result) -{ - if (state->digest_result_dma_addr) { - dma_unmap_single(dev, state->digest_result_dma_addr, digestsize, - DMA_BIDIRECTIONAL); - dev_dbg(dev, "unmpa digest result buffer va (%pK) pa (%pad) len %u\n", - state->digest_result_buff, - &state->digest_result_dma_addr, digestsize); - memcpy(result, state->digest_result_buff, digestsize); - } - state->digest_result_dma_addr = 0; -} - -static void cc_update_complete(struct device *dev, void *cc_req, int err) -{ - struct ahash_request *req = (struct ahash_request *)cc_req; - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - - dev_dbg(dev, "req=%pK\n", req); - - cc_unmap_hash_request(dev, state, req->src, false); - cc_unmap_req(dev, state, ctx); - req->base.complete(&req->base, err); -} - -static void cc_digest_complete(struct device *dev, void *cc_req, int err) -{ - struct ahash_request *req = (struct ahash_request *)cc_req; - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - u32 digestsize = crypto_ahash_digestsize(tfm); - - dev_dbg(dev, "req=%pK\n", req); - - cc_unmap_hash_request(dev, state, req->src, false); - cc_unmap_result(dev, state, digestsize, req->result); - cc_unmap_req(dev, state, ctx); - req->base.complete(&req->base, err); -} - -static void cc_hash_complete(struct device *dev, void *cc_req, int err) -{ - struct ahash_request *req = (struct ahash_request *)cc_req; - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - u32 digestsize = crypto_ahash_digestsize(tfm); - - dev_dbg(dev, "req=%pK\n", req); - - cc_unmap_hash_request(dev, state, req->src, false); - cc_unmap_result(dev, state, digestsize, req->result); - cc_unmap_req(dev, state, ctx); - req->base.complete(&req->base, err); -} - -static int cc_fin_result(struct cc_hw_desc *desc, struct ahash_request *req, - int idx) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - u32 digestsize = crypto_ahash_digestsize(tfm); - - /* Get final MAC result */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - /* TODO */ - set_dout_dlli(&desc[idx], state->digest_result_dma_addr, digestsize, - NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - cc_set_endianity(ctx->hash_mode, &desc[idx]); - idx++; - - return idx; -} - -static int cc_fin_hmac(struct cc_hw_desc *desc, struct ahash_request *req, - int idx) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - u32 digestsize = crypto_ahash_digestsize(tfm); - - /* store the hash digest result in the context */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_dout_dlli(&desc[idx], state->digest_buff_dma_addr, digestsize, - NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - cc_set_endianity(ctx->hash_mode, &desc[idx]); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - idx++; - - /* Loading hash opad xor key state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_din_type(&desc[idx], DMA_DLLI, state->opad_digest_dma_addr, - ctx->inter_digestsize, NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_din_sram(&desc[idx], - cc_digest_len_addr(ctx->drvdata, ctx->hash_mode), - HASH_LEN_SIZE); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Memory Barrier: wait for IPAD/OPAD axi write to complete */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - - /* Perform HASH update */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, - digestsize, NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - return idx; -} - -static int cc_hash_digest(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - u32 digestsize = crypto_ahash_digestsize(tfm); - struct scatterlist *src = req->src; - unsigned int nbytes = req->nbytes; - u8 *result = req->result; - struct device *dev = drvdata_to_dev(ctx->drvdata); - bool is_hmac = ctx->is_hmac; - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - cc_sram_addr_t larval_digest_addr = - cc_larval_digest_addr(ctx->drvdata, ctx->hash_mode); - int idx = 0; - int rc = 0; - gfp_t flags = cc_gfp_flags(&req->base); - - dev_dbg(dev, "===== %s-digest (%d) ====\n", is_hmac ? "hmac" : "hash", - nbytes); - - cc_init_req(dev, state, ctx); - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - return -ENOMEM; - } - - if (cc_map_result(dev, state, digestsize)) { - dev_err(dev, "map_ahash_digest() failed\n"); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - if (cc_map_hash_request_final(ctx->drvdata, state, src, nbytes, 1, - flags)) { - dev_err(dev, "map_ahash_request_final() failed\n"); - cc_unmap_result(dev, state, digestsize, result); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - /* Setup DX request structure */ - cc_req.user_cb = cc_digest_complete; - cc_req.user_arg = req; - - /* If HMAC then load hash IPAD xor key, if HASH then load initial - * digest - */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - if (is_hmac) { - set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, - ctx->inter_digestsize, NS_BIT); - } else { - set_din_sram(&desc[idx], larval_digest_addr, - ctx->inter_digestsize); - } - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - - if (is_hmac) { - set_din_type(&desc[idx], DMA_DLLI, - state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, - NS_BIT); - } else { - set_din_const(&desc[idx], 0, HASH_LEN_SIZE); - if (nbytes) - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - else - set_cipher_do(&desc[idx], DO_PAD); - } - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - cc_set_desc(state, ctx, DIN_HASH, desc, false, &idx); - - if (is_hmac) { - /* HW last hash block padding (aka. "DO_PAD") */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_dout_dlli(&desc[idx], state->digest_buff_dma_addr, - HASH_LEN_SIZE, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE1); - set_cipher_do(&desc[idx], DO_PAD); - idx++; - - idx = cc_fin_hmac(desc, req, idx); - } - - idx = cc_fin_result(desc, req, idx); - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, src, true); - cc_unmap_result(dev, state, digestsize, result); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_restore_hash(struct cc_hw_desc *desc, struct cc_hash_ctx *ctx, - struct ahash_req_ctx *state, int idx) -{ - /* Restore hash digest */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, - ctx->inter_digestsize, NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Restore hash current length */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - set_din_type(&desc[idx], DMA_DLLI, state->digest_bytes_len_dma_addr, - HASH_LEN_SIZE, NS_BIT); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - cc_set_desc(state, ctx, DIN_HASH, desc, false, &idx); - - return idx; -} - -static int cc_hash_update(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - unsigned int block_size = crypto_tfm_alg_blocksize(&tfm->base); - struct scatterlist *src = req->src; - unsigned int nbytes = req->nbytes; - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - u32 idx = 0; - int rc; - gfp_t flags = cc_gfp_flags(&req->base); - - dev_dbg(dev, "===== %s-update (%d) ====\n", ctx->is_hmac ? - "hmac" : "hash", nbytes); - - if (nbytes == 0) { - /* no real updates required */ - return 0; - } - - rc = cc_map_hash_request_update(ctx->drvdata, state, src, nbytes, - block_size, flags); - if (rc) { - if (rc == 1) { - dev_dbg(dev, " data size not require HW update %x\n", - nbytes); - /* No hardware updates are required */ - return 0; - } - dev_err(dev, "map_ahash_request_update() failed\n"); - return -ENOMEM; - } - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - cc_unmap_hash_request(dev, state, src, true); - return -EINVAL; - } - - /* Setup DX request structure */ - cc_req.user_cb = cc_update_complete; - cc_req.user_arg = req; - - idx = cc_restore_hash(desc, ctx, state, idx); - - /* store the hash digest result in context */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_dout_dlli(&desc[idx], state->digest_buff_dma_addr, - ctx->inter_digestsize, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - idx++; - - /* store current hash length in context */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_dout_dlli(&desc[idx], state->digest_bytes_len_dma_addr, - HASH_LEN_SIZE, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE1); - idx++; - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, src, true); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_hash_finup(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - u32 digestsize = crypto_ahash_digestsize(tfm); - struct scatterlist *src = req->src; - unsigned int nbytes = req->nbytes; - u8 *result = req->result; - struct device *dev = drvdata_to_dev(ctx->drvdata); - bool is_hmac = ctx->is_hmac; - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - int idx = 0; - int rc; - gfp_t flags = cc_gfp_flags(&req->base); - - dev_dbg(dev, "===== %s-finup (%d) ====\n", is_hmac ? "hmac" : "hash", - nbytes); - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - return -EINVAL; - } - - if (cc_map_hash_request_final(ctx->drvdata, state, src, nbytes, 1, - flags)) { - dev_err(dev, "map_ahash_request_final() failed\n"); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - if (cc_map_result(dev, state, digestsize)) { - dev_err(dev, "map_ahash_digest() failed\n"); - cc_unmap_hash_request(dev, state, src, true); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - /* Setup DX request structure */ - cc_req.user_cb = cc_hash_complete; - cc_req.user_arg = req; - - idx = cc_restore_hash(desc, ctx, state, idx); - - if (is_hmac) - idx = cc_fin_hmac(desc, req, idx); - - idx = cc_fin_result(desc, req, idx); - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, src, true); - cc_unmap_result(dev, state, digestsize, result); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_hash_final(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - u32 digestsize = crypto_ahash_digestsize(tfm); - struct scatterlist *src = req->src; - unsigned int nbytes = req->nbytes; - u8 *result = req->result; - struct device *dev = drvdata_to_dev(ctx->drvdata); - bool is_hmac = ctx->is_hmac; - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - int idx = 0; - int rc; - gfp_t flags = cc_gfp_flags(&req->base); - - dev_dbg(dev, "===== %s-final (%d) ====\n", is_hmac ? "hmac" : "hash", - nbytes); - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - return -EINVAL; - } - - if (cc_map_hash_request_final(ctx->drvdata, state, src, nbytes, 0, - flags)) { - dev_err(dev, "map_ahash_request_final() failed\n"); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - if (cc_map_result(dev, state, digestsize)) { - dev_err(dev, "map_ahash_digest() failed\n"); - cc_unmap_hash_request(dev, state, src, true); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - /* Setup DX request structure */ - cc_req.user_cb = cc_hash_complete; - cc_req.user_arg = req; - - idx = cc_restore_hash(desc, ctx, state, idx); - - /* "DO-PAD" must be enabled only when writing current length to HW */ - hw_desc_init(&desc[idx]); - set_cipher_do(&desc[idx], DO_PAD); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_dout_dlli(&desc[idx], state->digest_bytes_len_dma_addr, - HASH_LEN_SIZE, NS_BIT, 0); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE1); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - idx++; - - if (is_hmac) - idx = cc_fin_hmac(desc, req, idx); - - idx = cc_fin_result(desc, req, idx); - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, src, true); - cc_unmap_result(dev, state, digestsize, result); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_hash_init(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "===== init (%d) ====\n", req->nbytes); - - cc_init_req(dev, state, ctx); - - return 0; -} - -static int cc_hash_setkey(struct crypto_ahash *ahash, const u8 *key, - unsigned int keylen) -{ - unsigned int hmac_pad_const[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST }; - struct cc_crypto_req cc_req = {}; - struct cc_hash_ctx *ctx = NULL; - int blocksize = 0; - int digestsize = 0; - int i, idx = 0, rc = 0; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - cc_sram_addr_t larval_addr; - struct device *dev; - - ctx = crypto_ahash_ctx(ahash); - dev = drvdata_to_dev(ctx->drvdata); - dev_dbg(dev, "start keylen: %d", keylen); - - blocksize = crypto_tfm_alg_blocksize(&ahash->base); - digestsize = crypto_ahash_digestsize(ahash); - - larval_addr = cc_larval_digest_addr(ctx->drvdata, ctx->hash_mode); - - /* The keylen value distinguishes HASH in case keylen is ZERO bytes, - * any NON-ZERO value utilizes HMAC flow - */ - ctx->key_params.keylen = keylen; - ctx->key_params.key_dma_addr = 0; - ctx->is_hmac = true; - - if (keylen) { - ctx->key_params.key_dma_addr = - dma_map_single(dev, (void *)key, keylen, DMA_TO_DEVICE); - if (dma_mapping_error(dev, ctx->key_params.key_dma_addr)) { - dev_err(dev, "Mapping key va=0x%p len=%u for DMA failed\n", - key, keylen); - return -ENOMEM; - } - dev_dbg(dev, "mapping key-buffer: key_dma_addr=%pad keylen=%u\n", - &ctx->key_params.key_dma_addr, ctx->key_params.keylen); - - if (keylen > blocksize) { - /* Load hash initial state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_din_sram(&desc[idx], larval_addr, - ctx->inter_digestsize); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_din_const(&desc[idx], 0, HASH_LEN_SIZE); - set_cipher_config1(&desc[idx], HASH_PADDING_ENABLED); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - ctx->key_params.key_dma_addr, keylen, - NS_BIT); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Get hashed key */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_dout_dlli(&desc[idx], ctx->opad_tmp_keys_dma_addr, - digestsize, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config1(&desc[idx], HASH_PADDING_DISABLED); - cc_set_endianity(ctx->hash_mode, &desc[idx]); - idx++; - - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, (blocksize - digestsize)); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], - (ctx->opad_tmp_keys_dma_addr + - digestsize), - (blocksize - digestsize), NS_BIT, 0); - idx++; - } else { - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - ctx->key_params.key_dma_addr, keylen, - NS_BIT); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], ctx->opad_tmp_keys_dma_addr, - keylen, NS_BIT, 0); - idx++; - - if ((blocksize - keylen)) { - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, - (blocksize - keylen)); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], - (ctx->opad_tmp_keys_dma_addr + - keylen), (blocksize - keylen), - NS_BIT, 0); - idx++; - } - } - } else { - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0, blocksize); - set_flow_mode(&desc[idx], BYPASS); - set_dout_dlli(&desc[idx], (ctx->opad_tmp_keys_dma_addr), - blocksize, NS_BIT, 0); - idx++; - } - - rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx); - if (rc) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - goto out; - } - - /* calc derived HMAC key */ - for (idx = 0, i = 0; i < 2; i++) { - /* Load hash initial state */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_din_sram(&desc[idx], larval_addr, ctx->inter_digestsize); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - idx++; - - /* Load the hash current length*/ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_din_const(&desc[idx], 0, HASH_LEN_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Prepare ipad key */ - hw_desc_init(&desc[idx]); - set_xor_val(&desc[idx], hmac_pad_const[i]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_flow_mode(&desc[idx], S_DIN_to_HASH); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - idx++; - - /* Perform HASH update */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, ctx->opad_tmp_keys_dma_addr, - blocksize, NS_BIT); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_xor_active(&desc[idx]); - set_flow_mode(&desc[idx], DIN_HASH); - idx++; - - /* Get the IPAD/OPAD xor key (Note, IPAD is the initial digest - * of the first HASH "update" state) - */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - if (i > 0) /* Not first iteration */ - set_dout_dlli(&desc[idx], ctx->opad_tmp_keys_dma_addr, - ctx->inter_digestsize, NS_BIT, 0); - else /* First iteration */ - set_dout_dlli(&desc[idx], ctx->digest_buff_dma_addr, - ctx->inter_digestsize, NS_BIT, 0); - set_flow_mode(&desc[idx], S_HASH_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - idx++; - } - - rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx); - -out: - if (rc) - crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN); - - if (ctx->key_params.key_dma_addr) { - dma_unmap_single(dev, ctx->key_params.key_dma_addr, - ctx->key_params.keylen, DMA_TO_DEVICE); - dev_dbg(dev, "Unmapped key-buffer: key_dma_addr=%pad keylen=%u\n", - &ctx->key_params.key_dma_addr, ctx->key_params.keylen); - } - return rc; -} - -static int cc_xcbc_setkey(struct crypto_ahash *ahash, - const u8 *key, unsigned int keylen) -{ - struct cc_crypto_req cc_req = {}; - struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash); - struct device *dev = drvdata_to_dev(ctx->drvdata); - int idx = 0, rc = 0; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - - dev_dbg(dev, "===== setkey (%d) ====\n", keylen); - - switch (keylen) { - case AES_KEYSIZE_128: - case AES_KEYSIZE_192: - case AES_KEYSIZE_256: - break; - default: - return -EINVAL; - } - - ctx->key_params.keylen = keylen; - - ctx->key_params.key_dma_addr = - dma_map_single(dev, (void *)key, keylen, DMA_TO_DEVICE); - if (dma_mapping_error(dev, ctx->key_params.key_dma_addr)) { - dev_err(dev, "Mapping key va=0x%p len=%u for DMA failed\n", - key, keylen); - return -ENOMEM; - } - dev_dbg(dev, "mapping key-buffer: key_dma_addr=%pad keylen=%u\n", - &ctx->key_params.key_dma_addr, ctx->key_params.keylen); - - ctx->is_hmac = true; - /* 1. Load the AES key */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, ctx->key_params.key_dma_addr, - keylen, NS_BIT); - set_cipher_mode(&desc[idx], DRV_CIPHER_ECB); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT); - set_key_size_aes(&desc[idx], keylen); - set_flow_mode(&desc[idx], S_DIN_to_AES); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x01010101, CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - set_dout_dlli(&desc[idx], - (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K1_OFFSET), - CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0); - idx++; - - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x02020202, CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - set_dout_dlli(&desc[idx], - (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K2_OFFSET), - CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0); - idx++; - - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x03030303, CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - set_dout_dlli(&desc[idx], - (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K3_OFFSET), - CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0); - idx++; - - rc = cc_send_sync_request(ctx->drvdata, &cc_req, desc, idx); - - if (rc) - crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN); - - dma_unmap_single(dev, ctx->key_params.key_dma_addr, - ctx->key_params.keylen, DMA_TO_DEVICE); - dev_dbg(dev, "Unmapped key-buffer: key_dma_addr=%pad keylen=%u\n", - &ctx->key_params.key_dma_addr, ctx->key_params.keylen); - - return rc; -} - -static int cc_cmac_setkey(struct crypto_ahash *ahash, - const u8 *key, unsigned int keylen) -{ - struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "===== setkey (%d) ====\n", keylen); - - ctx->is_hmac = true; - - switch (keylen) { - case AES_KEYSIZE_128: - case AES_KEYSIZE_192: - case AES_KEYSIZE_256: - break; - default: - return -EINVAL; - } - - ctx->key_params.keylen = keylen; - - /* STAT_PHASE_1: Copy key to ctx */ - - dma_sync_single_for_cpu(dev, ctx->opad_tmp_keys_dma_addr, - keylen, DMA_TO_DEVICE); - - memcpy(ctx->opad_tmp_keys_buff, key, keylen); - if (keylen == 24) { - memset(ctx->opad_tmp_keys_buff + 24, 0, - CC_AES_KEY_SIZE_MAX - 24); - } - - dma_sync_single_for_device(dev, ctx->opad_tmp_keys_dma_addr, - keylen, DMA_TO_DEVICE); - - ctx->key_params.keylen = keylen; - - return 0; -} - -static void cc_free_ctx(struct cc_hash_ctx *ctx) -{ - struct device *dev = drvdata_to_dev(ctx->drvdata); - - if (ctx->digest_buff_dma_addr) { - dma_unmap_single(dev, ctx->digest_buff_dma_addr, - sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL); - dev_dbg(dev, "Unmapped digest-buffer: digest_buff_dma_addr=%pad\n", - &ctx->digest_buff_dma_addr); - ctx->digest_buff_dma_addr = 0; - } - if (ctx->opad_tmp_keys_dma_addr) { - dma_unmap_single(dev, ctx->opad_tmp_keys_dma_addr, - sizeof(ctx->opad_tmp_keys_buff), - DMA_BIDIRECTIONAL); - dev_dbg(dev, "Unmapped opad-digest: opad_tmp_keys_dma_addr=%pad\n", - &ctx->opad_tmp_keys_dma_addr); - ctx->opad_tmp_keys_dma_addr = 0; - } - - ctx->key_params.keylen = 0; -} - -static int cc_alloc_ctx(struct cc_hash_ctx *ctx) -{ - struct device *dev = drvdata_to_dev(ctx->drvdata); - - ctx->key_params.keylen = 0; - - ctx->digest_buff_dma_addr = - dma_map_single(dev, (void *)ctx->digest_buff, - sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, ctx->digest_buff_dma_addr)) { - dev_err(dev, "Mapping digest len %zu B at va=%pK for DMA failed\n", - sizeof(ctx->digest_buff), ctx->digest_buff); - goto fail; - } - dev_dbg(dev, "Mapped digest %zu B at va=%pK to dma=%pad\n", - sizeof(ctx->digest_buff), ctx->digest_buff, - &ctx->digest_buff_dma_addr); - - ctx->opad_tmp_keys_dma_addr = - dma_map_single(dev, (void *)ctx->opad_tmp_keys_buff, - sizeof(ctx->opad_tmp_keys_buff), - DMA_BIDIRECTIONAL); - if (dma_mapping_error(dev, ctx->opad_tmp_keys_dma_addr)) { - dev_err(dev, "Mapping opad digest %zu B at va=%pK for DMA failed\n", - sizeof(ctx->opad_tmp_keys_buff), - ctx->opad_tmp_keys_buff); - goto fail; - } - dev_dbg(dev, "Mapped opad_tmp_keys %zu B at va=%pK to dma=%pad\n", - sizeof(ctx->opad_tmp_keys_buff), ctx->opad_tmp_keys_buff, - &ctx->opad_tmp_keys_dma_addr); - - ctx->is_hmac = false; - return 0; - -fail: - cc_free_ctx(ctx); - return -ENOMEM; -} - -static int cc_cra_init(struct crypto_tfm *tfm) -{ - struct cc_hash_ctx *ctx = crypto_tfm_ctx(tfm); - struct hash_alg_common *hash_alg_common = - container_of(tfm->__crt_alg, struct hash_alg_common, base); - struct ahash_alg *ahash_alg = - container_of(hash_alg_common, struct ahash_alg, halg); - struct cc_hash_alg *cc_alg = - container_of(ahash_alg, struct cc_hash_alg, ahash_alg); - - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct ahash_req_ctx)); - - ctx->hash_mode = cc_alg->hash_mode; - ctx->hw_mode = cc_alg->hw_mode; - ctx->inter_digestsize = cc_alg->inter_digestsize; - ctx->drvdata = cc_alg->drvdata; - - return cc_alloc_ctx(ctx); -} - -static void cc_cra_exit(struct crypto_tfm *tfm) -{ - struct cc_hash_ctx *ctx = crypto_tfm_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - - dev_dbg(dev, "cc_cra_exit"); - cc_free_ctx(ctx); -} - -static int cc_mac_update(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - unsigned int block_size = crypto_tfm_alg_blocksize(&tfm->base); - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - int rc; - u32 idx = 0; - gfp_t flags = cc_gfp_flags(&req->base); - - if (req->nbytes == 0) { - /* no real updates required */ - return 0; - } - - state->xcbc_count++; - - rc = cc_map_hash_request_update(ctx->drvdata, state, req->src, - req->nbytes, block_size, flags); - if (rc) { - if (rc == 1) { - dev_dbg(dev, " data size not require HW update %x\n", - req->nbytes); - /* No hardware updates are required */ - return 0; - } - dev_err(dev, "map_ahash_request_update() failed\n"); - return -ENOMEM; - } - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - return -EINVAL; - } - - if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) - cc_setup_xcbc(req, desc, &idx); - else - cc_setup_cmac(req, desc, &idx); - - cc_set_desc(state, ctx, DIN_AES_DOUT, desc, true, &idx); - - /* store the hash digest result in context */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_dout_dlli(&desc[idx], state->digest_buff_dma_addr, - ctx->inter_digestsize, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], S_AES_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - idx++; - - /* Setup DX request structure */ - cc_req.user_cb = (void *)cc_update_complete; - cc_req.user_arg = (void *)req; - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, req->src, true); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_mac_final(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - int idx = 0; - int rc = 0; - u32 key_size, key_len; - u32 digestsize = crypto_ahash_digestsize(tfm); - gfp_t flags = cc_gfp_flags(&req->base); - u32 rem_cnt = *cc_hash_buf_cnt(state); - - if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) { - key_size = CC_AES_128_BIT_KEY_SIZE; - key_len = CC_AES_128_BIT_KEY_SIZE; - } else { - key_size = (ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE : - ctx->key_params.keylen; - key_len = ctx->key_params.keylen; - } - - dev_dbg(dev, "===== final xcbc reminder (%d) ====\n", rem_cnt); - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - return -EINVAL; - } - - if (cc_map_hash_request_final(ctx->drvdata, state, req->src, - req->nbytes, 0, flags)) { - dev_err(dev, "map_ahash_request_final() failed\n"); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - if (cc_map_result(dev, state, digestsize)) { - dev_err(dev, "map_ahash_digest() failed\n"); - cc_unmap_hash_request(dev, state, req->src, true); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - /* Setup DX request structure */ - cc_req.user_cb = (void *)cc_hash_complete; - cc_req.user_arg = (void *)req; - - if (state->xcbc_count && rem_cnt == 0) { - /* Load key for ECB decryption */ - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], DRV_CIPHER_ECB); - set_cipher_config0(&desc[idx], DRV_CRYPTO_DIRECTION_DECRYPT); - set_din_type(&desc[idx], DMA_DLLI, - (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K1_OFFSET), - key_size, NS_BIT); - set_key_size_aes(&desc[idx], key_len); - set_flow_mode(&desc[idx], S_DIN_to_AES); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - idx++; - - /* Initiate decryption of block state to previous - * block_state-XOR-M[n] - */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, - CC_AES_BLOCK_SIZE, NS_BIT); - set_dout_dlli(&desc[idx], state->digest_buff_dma_addr, - CC_AES_BLOCK_SIZE, NS_BIT, 0); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - - /* Memory Barrier: wait for axi write to complete */ - hw_desc_init(&desc[idx]); - set_din_no_dma(&desc[idx], 0, 0xfffff0); - set_dout_no_dma(&desc[idx], 0, 0, 1); - idx++; - } - - if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) - cc_setup_xcbc(req, desc, &idx); - else - cc_setup_cmac(req, desc, &idx); - - if (state->xcbc_count == 0) { - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_key_size_aes(&desc[idx], key_len); - set_cmac_size0_mode(&desc[idx]); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - } else if (rem_cnt > 0) { - cc_set_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx); - } else { - hw_desc_init(&desc[idx]); - set_din_const(&desc[idx], 0x00, CC_AES_BLOCK_SIZE); - set_flow_mode(&desc[idx], DIN_AES_DOUT); - idx++; - } - - /* Get final MAC result */ - hw_desc_init(&desc[idx]); - /* TODO */ - set_dout_dlli(&desc[idx], state->digest_result_dma_addr, - digestsize, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], S_AES_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_mode(&desc[idx], ctx->hw_mode); - idx++; - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, req->src, true); - cc_unmap_result(dev, state, digestsize, req->result); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_mac_finup(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - int idx = 0; - int rc = 0; - u32 key_len = 0; - u32 digestsize = crypto_ahash_digestsize(tfm); - gfp_t flags = cc_gfp_flags(&req->base); - - dev_dbg(dev, "===== finup xcbc(%d) ====\n", req->nbytes); - if (state->xcbc_count > 0 && req->nbytes == 0) { - dev_dbg(dev, "No data to update. Call to fdx_mac_final\n"); - return cc_mac_final(req); - } - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - return -EINVAL; - } - - if (cc_map_hash_request_final(ctx->drvdata, state, req->src, - req->nbytes, 1, flags)) { - dev_err(dev, "map_ahash_request_final() failed\n"); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - if (cc_map_result(dev, state, digestsize)) { - dev_err(dev, "map_ahash_digest() failed\n"); - cc_unmap_hash_request(dev, state, req->src, true); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - /* Setup DX request structure */ - cc_req.user_cb = (void *)cc_hash_complete; - cc_req.user_arg = (void *)req; - - if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) { - key_len = CC_AES_128_BIT_KEY_SIZE; - cc_setup_xcbc(req, desc, &idx); - } else { - key_len = ctx->key_params.keylen; - cc_setup_cmac(req, desc, &idx); - } - - if (req->nbytes == 0) { - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_key_size_aes(&desc[idx], key_len); - set_cmac_size0_mode(&desc[idx]); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - } else { - cc_set_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx); - } - - /* Get final MAC result */ - hw_desc_init(&desc[idx]); - /* TODO */ - set_dout_dlli(&desc[idx], state->digest_result_dma_addr, - digestsize, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], S_AES_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_mode(&desc[idx], ctx->hw_mode); - idx++; - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, req->src, true); - cc_unmap_result(dev, state, digestsize, req->result); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_mac_digest(struct ahash_request *req) -{ - struct ahash_req_ctx *state = ahash_request_ctx(req); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - struct device *dev = drvdata_to_dev(ctx->drvdata); - u32 digestsize = crypto_ahash_digestsize(tfm); - struct cc_crypto_req cc_req = {}; - struct cc_hw_desc desc[CC_MAX_HASH_SEQ_LEN]; - u32 key_len; - int idx = 0; - int rc; - gfp_t flags = cc_gfp_flags(&req->base); - - dev_dbg(dev, "===== -digest mac (%d) ====\n", req->nbytes); - - cc_init_req(dev, state, ctx); - - if (cc_map_req(dev, state, ctx)) { - dev_err(dev, "map_ahash_source() failed\n"); - return -ENOMEM; - } - if (cc_map_result(dev, state, digestsize)) { - dev_err(dev, "map_ahash_digest() failed\n"); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - if (cc_map_hash_request_final(ctx->drvdata, state, req->src, - req->nbytes, 1, flags)) { - dev_err(dev, "map_ahash_request_final() failed\n"); - cc_unmap_req(dev, state, ctx); - return -ENOMEM; - } - - /* Setup DX request structure */ - cc_req.user_cb = (void *)cc_digest_complete; - cc_req.user_arg = (void *)req; - - if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) { - key_len = CC_AES_128_BIT_KEY_SIZE; - cc_setup_xcbc(req, desc, &idx); - } else { - key_len = ctx->key_params.keylen; - cc_setup_cmac(req, desc, &idx); - } - - if (req->nbytes == 0) { - hw_desc_init(&desc[idx]); - set_cipher_mode(&desc[idx], ctx->hw_mode); - set_key_size_aes(&desc[idx], key_len); - set_cmac_size0_mode(&desc[idx]); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - } else { - cc_set_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx); - } - - /* Get final MAC result */ - hw_desc_init(&desc[idx]); - set_dout_dlli(&desc[idx], state->digest_result_dma_addr, - CC_AES_BLOCK_SIZE, NS_BIT, 1); - set_queue_last_ind(&desc[idx]); - set_flow_mode(&desc[idx], S_AES_to_DOUT); - set_setup_mode(&desc[idx], SETUP_WRITE_STATE0); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_cipher_mode(&desc[idx], ctx->hw_mode); - idx++; - - rc = cc_send_request(ctx->drvdata, &cc_req, desc, idx, &req->base); - if (rc != -EINPROGRESS && rc != -EBUSY) { - dev_err(dev, "send_request() failed (rc=%d)\n", rc); - cc_unmap_hash_request(dev, state, req->src, true); - cc_unmap_result(dev, state, digestsize, req->result); - cc_unmap_req(dev, state, ctx); - } - return rc; -} - -static int cc_hash_export(struct ahash_request *req, void *out) -{ - struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash); - struct ahash_req_ctx *state = ahash_request_ctx(req); - u8 *curr_buff = cc_hash_buf(state); - u32 curr_buff_cnt = *cc_hash_buf_cnt(state); - const u32 tmp = CC_EXPORT_MAGIC; - - memcpy(out, &tmp, sizeof(u32)); - out += sizeof(u32); - - memcpy(out, state->digest_buff, ctx->inter_digestsize); - out += ctx->inter_digestsize; - - memcpy(out, state->digest_bytes_len, HASH_LEN_SIZE); - out += HASH_LEN_SIZE; - - memcpy(out, &curr_buff_cnt, sizeof(u32)); - out += sizeof(u32); - - memcpy(out, curr_buff, curr_buff_cnt); - - return 0; -} - -static int cc_hash_import(struct ahash_request *req, const void *in) -{ - struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(ahash); - struct device *dev = drvdata_to_dev(ctx->drvdata); - struct ahash_req_ctx *state = ahash_request_ctx(req); - u32 tmp; - - memcpy(&tmp, in, sizeof(u32)); - if (tmp != CC_EXPORT_MAGIC) - return -EINVAL; - in += sizeof(u32); - - cc_init_req(dev, state, ctx); - - memcpy(state->digest_buff, in, ctx->inter_digestsize); - in += ctx->inter_digestsize; - - memcpy(state->digest_bytes_len, in, HASH_LEN_SIZE); - in += HASH_LEN_SIZE; - - /* Sanity check the data as much as possible */ - memcpy(&tmp, in, sizeof(u32)); - if (tmp > CC_MAX_HASH_BLCK_SIZE) - return -EINVAL; - in += sizeof(u32); - - state->buf_cnt[0] = tmp; - memcpy(state->buffers[0], in, tmp); - - return 0; -} - -struct cc_hash_template { - char name[CRYPTO_MAX_ALG_NAME]; - char driver_name[CRYPTO_MAX_ALG_NAME]; - char mac_name[CRYPTO_MAX_ALG_NAME]; - char mac_driver_name[CRYPTO_MAX_ALG_NAME]; - unsigned int blocksize; - bool synchronize; - struct ahash_alg template_ahash; - int hash_mode; - int hw_mode; - int inter_digestsize; - struct cc_drvdata *drvdata; -}; - -#define CC_STATE_SIZE(_x) \ - ((_x) + HASH_LEN_SIZE + CC_MAX_HASH_BLCK_SIZE + (2 * sizeof(u32))) - -/* hash descriptors */ -static struct cc_hash_template driver_hash[] = { - //Asynchronize hash template - { - .name = "sha1", - .driver_name = "sha1-dx", - .mac_name = "hmac(sha1)", - .mac_driver_name = "hmac-sha1-dx", - .blocksize = SHA1_BLOCK_SIZE, - .synchronize = false, - .template_ahash = { - .init = cc_hash_init, - .update = cc_hash_update, - .final = cc_hash_final, - .finup = cc_hash_finup, - .digest = cc_hash_digest, - .export = cc_hash_export, - .import = cc_hash_import, - .setkey = cc_hash_setkey, - .halg = { - .digestsize = SHA1_DIGEST_SIZE, - .statesize = CC_STATE_SIZE(SHA1_DIGEST_SIZE), - }, - }, - .hash_mode = DRV_HASH_SHA1, - .hw_mode = DRV_HASH_HW_SHA1, - .inter_digestsize = SHA1_DIGEST_SIZE, - }, - { - .name = "sha256", - .driver_name = "sha256-dx", - .mac_name = "hmac(sha256)", - .mac_driver_name = "hmac-sha256-dx", - .blocksize = SHA256_BLOCK_SIZE, - .template_ahash = { - .init = cc_hash_init, - .update = cc_hash_update, - .final = cc_hash_final, - .finup = cc_hash_finup, - .digest = cc_hash_digest, - .export = cc_hash_export, - .import = cc_hash_import, - .setkey = cc_hash_setkey, - .halg = { - .digestsize = SHA256_DIGEST_SIZE, - .statesize = CC_STATE_SIZE(SHA256_DIGEST_SIZE) - }, - }, - .hash_mode = DRV_HASH_SHA256, - .hw_mode = DRV_HASH_HW_SHA256, - .inter_digestsize = SHA256_DIGEST_SIZE, - }, - { - .name = "sha224", - .driver_name = "sha224-dx", - .mac_name = "hmac(sha224)", - .mac_driver_name = "hmac-sha224-dx", - .blocksize = SHA224_BLOCK_SIZE, - .template_ahash = { - .init = cc_hash_init, - .update = cc_hash_update, - .final = cc_hash_final, - .finup = cc_hash_finup, - .digest = cc_hash_digest, - .export = cc_hash_export, - .import = cc_hash_import, - .setkey = cc_hash_setkey, - .halg = { - .digestsize = SHA224_DIGEST_SIZE, - .statesize = CC_STATE_SIZE(SHA224_DIGEST_SIZE), - }, - }, - .hash_mode = DRV_HASH_SHA224, - .hw_mode = DRV_HASH_HW_SHA256, - .inter_digestsize = SHA256_DIGEST_SIZE, - }, -#if (CC_DEV_SHA_MAX > 256) - { - .name = "sha384", - .driver_name = "sha384-dx", - .mac_name = "hmac(sha384)", - .mac_driver_name = "hmac-sha384-dx", - .blocksize = SHA384_BLOCK_SIZE, - .template_ahash = { - .init = cc_hash_init, - .update = cc_hash_update, - .final = cc_hash_final, - .finup = cc_hash_finup, - .digest = cc_hash_digest, - .export = cc_hash_export, - .import = cc_hash_import, - .setkey = cc_hash_setkey, - .halg = { - .digestsize = SHA384_DIGEST_SIZE, - .statesize = CC_STATE_SIZE(SHA384_DIGEST_SIZE), - }, - }, - .hash_mode = DRV_HASH_SHA384, - .hw_mode = DRV_HASH_HW_SHA512, - .inter_digestsize = SHA512_DIGEST_SIZE, - }, - { - .name = "sha512", - .driver_name = "sha512-dx", - .mac_name = "hmac(sha512)", - .mac_driver_name = "hmac-sha512-dx", - .blocksize = SHA512_BLOCK_SIZE, - .template_ahash = { - .init = cc_hash_init, - .update = cc_hash_update, - .final = cc_hash_final, - .finup = cc_hash_finup, - .digest = cc_hash_digest, - .export = cc_hash_export, - .import = cc_hash_import, - .setkey = cc_hash_setkey, - .halg = { - .digestsize = SHA512_DIGEST_SIZE, - .statesize = CC_STATE_SIZE(SHA512_DIGEST_SIZE), - }, - }, - .hash_mode = DRV_HASH_SHA512, - .hw_mode = DRV_HASH_HW_SHA512, - .inter_digestsize = SHA512_DIGEST_SIZE, - }, -#endif - { - .name = "md5", - .driver_name = "md5-dx", - .mac_name = "hmac(md5)", - .mac_driver_name = "hmac-md5-dx", - .blocksize = MD5_HMAC_BLOCK_SIZE, - .template_ahash = { - .init = cc_hash_init, - .update = cc_hash_update, - .final = cc_hash_final, - .finup = cc_hash_finup, - .digest = cc_hash_digest, - .export = cc_hash_export, - .import = cc_hash_import, - .setkey = cc_hash_setkey, - .halg = { - .digestsize = MD5_DIGEST_SIZE, - .statesize = CC_STATE_SIZE(MD5_DIGEST_SIZE), - }, - }, - .hash_mode = DRV_HASH_MD5, - .hw_mode = DRV_HASH_HW_MD5, - .inter_digestsize = MD5_DIGEST_SIZE, - }, - { - .mac_name = "xcbc(aes)", - .mac_driver_name = "xcbc-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .template_ahash = { - .init = cc_hash_init, - .update = cc_mac_update, - .final = cc_mac_final, - .finup = cc_mac_finup, - .digest = cc_mac_digest, - .setkey = cc_xcbc_setkey, - .export = cc_hash_export, - .import = cc_hash_import, - .halg = { - .digestsize = AES_BLOCK_SIZE, - .statesize = CC_STATE_SIZE(AES_BLOCK_SIZE), - }, - }, - .hash_mode = DRV_HASH_NULL, - .hw_mode = DRV_CIPHER_XCBC_MAC, - .inter_digestsize = AES_BLOCK_SIZE, - }, - { - .mac_name = "cmac(aes)", - .mac_driver_name = "cmac-aes-dx", - .blocksize = AES_BLOCK_SIZE, - .template_ahash = { - .init = cc_hash_init, - .update = cc_mac_update, - .final = cc_mac_final, - .finup = cc_mac_finup, - .digest = cc_mac_digest, - .setkey = cc_cmac_setkey, - .export = cc_hash_export, - .import = cc_hash_import, - .halg = { - .digestsize = AES_BLOCK_SIZE, - .statesize = CC_STATE_SIZE(AES_BLOCK_SIZE), - }, - }, - .hash_mode = DRV_HASH_NULL, - .hw_mode = DRV_CIPHER_CMAC, - .inter_digestsize = AES_BLOCK_SIZE, - }, -}; - -static struct cc_hash_alg *cc_alloc_hash_alg(struct cc_hash_template *template, - struct device *dev, bool keyed) -{ - struct cc_hash_alg *t_crypto_alg; - struct crypto_alg *alg; - struct ahash_alg *halg; - - t_crypto_alg = kzalloc(sizeof(*t_crypto_alg), GFP_KERNEL); - if (!t_crypto_alg) - return ERR_PTR(-ENOMEM); - - t_crypto_alg->ahash_alg = template->template_ahash; - halg = &t_crypto_alg->ahash_alg; - alg = &halg->halg.base; - - if (keyed) { - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", - template->mac_name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->mac_driver_name); - } else { - halg->setkey = NULL; - snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", - template->name); - snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - template->driver_name); - } - alg->cra_module = THIS_MODULE; - alg->cra_ctxsize = sizeof(struct cc_hash_ctx); - alg->cra_priority = CC_CRA_PRIO; - alg->cra_blocksize = template->blocksize; - alg->cra_alignmask = 0; - alg->cra_exit = cc_cra_exit; - - alg->cra_init = cc_cra_init; - alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_KERN_DRIVER_ONLY; - alg->cra_type = &crypto_ahash_type; - - t_crypto_alg->hash_mode = template->hash_mode; - t_crypto_alg->hw_mode = template->hw_mode; - t_crypto_alg->inter_digestsize = template->inter_digestsize; - - return t_crypto_alg; -} - -int cc_init_hash_sram(struct cc_drvdata *drvdata) -{ - struct cc_hash_handle *hash_handle = drvdata->hash_handle; - cc_sram_addr_t sram_buff_ofs = hash_handle->digest_len_sram_addr; - unsigned int larval_seq_len = 0; - struct cc_hw_desc larval_seq[CC_DIGEST_SIZE_MAX / sizeof(u32)]; - int rc = 0; - - /* Copy-to-sram digest-len */ - cc_set_sram_desc(digest_len_init, sram_buff_ofs, - ARRAY_SIZE(digest_len_init), larval_seq, - &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; - - sram_buff_ofs += sizeof(digest_len_init); - larval_seq_len = 0; - -#if (CC_DEV_SHA_MAX > 256) - /* Copy-to-sram digest-len for sha384/512 */ - cc_set_sram_desc(digest_len_sha512_init, sram_buff_ofs, - ARRAY_SIZE(digest_len_sha512_init), - larval_seq, &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; - - sram_buff_ofs += sizeof(digest_len_sha512_init); - larval_seq_len = 0; -#endif - - /* The initial digests offset */ - hash_handle->larval_digest_sram_addr = sram_buff_ofs; - - /* Copy-to-sram initial SHA* digests */ - cc_set_sram_desc(md5_init, sram_buff_ofs, ARRAY_SIZE(md5_init), - larval_seq, &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; - sram_buff_ofs += sizeof(md5_init); - larval_seq_len = 0; - - cc_set_sram_desc(sha1_init, sram_buff_ofs, - ARRAY_SIZE(sha1_init), larval_seq, - &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; - sram_buff_ofs += sizeof(sha1_init); - larval_seq_len = 0; - - cc_set_sram_desc(sha224_init, sram_buff_ofs, - ARRAY_SIZE(sha224_init), larval_seq, - &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; - sram_buff_ofs += sizeof(sha224_init); - larval_seq_len = 0; - - cc_set_sram_desc(sha256_init, sram_buff_ofs, - ARRAY_SIZE(sha256_init), larval_seq, - &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; - sram_buff_ofs += sizeof(sha256_init); - larval_seq_len = 0; - -#if (CC_DEV_SHA_MAX > 256) - cc_set_sram_desc((u32 *)sha384_init, sram_buff_ofs, - (ARRAY_SIZE(sha384_init) * 2), larval_seq, - &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; - sram_buff_ofs += sizeof(sha384_init); - larval_seq_len = 0; - - cc_set_sram_desc((u32 *)sha512_init, sram_buff_ofs, - (ARRAY_SIZE(sha512_init) * 2), larval_seq, - &larval_seq_len); - rc = send_request_init(drvdata, larval_seq, larval_seq_len); - if (rc) - goto init_digest_const_err; -#endif - -init_digest_const_err: - return rc; -} - -static void __init cc_swap_dwords(u32 *buf, unsigned long size) -{ - int i; - u32 tmp; - - for (i = 0; i < size; i += 2) { - tmp = buf[i]; - buf[i] = buf[i + 1]; - buf[i + 1] = tmp; - } -} - -/* - * Due to the way the HW works we need to swap every - * double word in the SHA384 and SHA512 larval hashes - */ -void __init cc_hash_global_init(void) -{ - cc_swap_dwords((u32 *)&sha384_init, (ARRAY_SIZE(sha384_init) * 2)); - cc_swap_dwords((u32 *)&sha512_init, (ARRAY_SIZE(sha512_init) * 2)); -} - -int cc_hash_alloc(struct cc_drvdata *drvdata) -{ - struct cc_hash_handle *hash_handle; - cc_sram_addr_t sram_buff; - u32 sram_size_to_alloc; - struct device *dev = drvdata_to_dev(drvdata); - int rc = 0; - int alg; - - hash_handle = kzalloc(sizeof(*hash_handle), GFP_KERNEL); - if (!hash_handle) - return -ENOMEM; - - INIT_LIST_HEAD(&hash_handle->hash_list); - drvdata->hash_handle = hash_handle; - - sram_size_to_alloc = sizeof(digest_len_init) + -#if (CC_DEV_SHA_MAX > 256) - sizeof(digest_len_sha512_init) + - sizeof(sha384_init) + - sizeof(sha512_init) + -#endif - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init) + - sizeof(sha256_init); - - sram_buff = cc_sram_alloc(drvdata, sram_size_to_alloc); - if (sram_buff == NULL_SRAM_ADDR) { - dev_err(dev, "SRAM pool exhausted\n"); - rc = -ENOMEM; - goto fail; - } - - /* The initial digest-len offset */ - hash_handle->digest_len_sram_addr = sram_buff; - - /*must be set before the alg registration as it is being used there*/ - rc = cc_init_hash_sram(drvdata); - if (rc) { - dev_err(dev, "Init digest CONST failed (rc=%d)\n", rc); - goto fail; - } - - /* ahash registration */ - for (alg = 0; alg < ARRAY_SIZE(driver_hash); alg++) { - struct cc_hash_alg *t_alg; - int hw_mode = driver_hash[alg].hw_mode; - - /* register hmac version */ - t_alg = cc_alloc_hash_alg(&driver_hash[alg], dev, true); - if (IS_ERR(t_alg)) { - rc = PTR_ERR(t_alg); - dev_err(dev, "%s alg allocation failed\n", - driver_hash[alg].driver_name); - goto fail; - } - t_alg->drvdata = drvdata; - - rc = crypto_register_ahash(&t_alg->ahash_alg); - if (rc) { - dev_err(dev, "%s alg registration failed\n", - driver_hash[alg].driver_name); - kfree(t_alg); - goto fail; - } else { - list_add_tail(&t_alg->entry, &hash_handle->hash_list); - } - - if (hw_mode == DRV_CIPHER_XCBC_MAC || - hw_mode == DRV_CIPHER_CMAC) - continue; - - /* register hash version */ - t_alg = cc_alloc_hash_alg(&driver_hash[alg], dev, false); - if (IS_ERR(t_alg)) { - rc = PTR_ERR(t_alg); - dev_err(dev, "%s alg allocation failed\n", - driver_hash[alg].driver_name); - goto fail; - } - t_alg->drvdata = drvdata; - - rc = crypto_register_ahash(&t_alg->ahash_alg); - if (rc) { - dev_err(dev, "%s alg registration failed\n", - driver_hash[alg].driver_name); - kfree(t_alg); - goto fail; - } else { - list_add_tail(&t_alg->entry, &hash_handle->hash_list); - } - } - - return 0; - -fail: - kfree(drvdata->hash_handle); - drvdata->hash_handle = NULL; - return rc; -} - -int cc_hash_free(struct cc_drvdata *drvdata) -{ - struct cc_hash_alg *t_hash_alg, *hash_n; - struct cc_hash_handle *hash_handle = drvdata->hash_handle; - - if (hash_handle) { - list_for_each_entry_safe(t_hash_alg, hash_n, - &hash_handle->hash_list, entry) { - crypto_unregister_ahash(&t_hash_alg->ahash_alg); - list_del(&t_hash_alg->entry); - kfree(t_hash_alg); - } - - kfree(hash_handle); - drvdata->hash_handle = NULL; - } - return 0; -} - -static void cc_setup_xcbc(struct ahash_request *areq, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - unsigned int idx = *seq_size; - struct ahash_req_ctx *state = ahash_request_ctx(areq); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - - /* Setup XCBC MAC K1 */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, (ctx->opad_tmp_keys_dma_addr + - XCBC_MAC_K1_OFFSET), - CC_AES_128_BIT_KEY_SIZE, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Setup XCBC MAC K2 */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K2_OFFSET), - CC_AES_128_BIT_KEY_SIZE, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE1); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Setup XCBC MAC K3 */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - (ctx->opad_tmp_keys_dma_addr + XCBC_MAC_K3_OFFSET), - CC_AES_128_BIT_KEY_SIZE, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE2); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Loading MAC state */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, - CC_AES_BLOCK_SIZE, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - set_cipher_mode(&desc[idx], DRV_CIPHER_XCBC_MAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], CC_AES_128_BIT_KEY_SIZE); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - *seq_size = idx; -} - -static void cc_setup_cmac(struct ahash_request *areq, struct cc_hw_desc desc[], - unsigned int *seq_size) -{ - unsigned int idx = *seq_size; - struct ahash_req_ctx *state = ahash_request_ctx(areq); - struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); - struct cc_hash_ctx *ctx = crypto_ahash_ctx(tfm); - - /* Setup CMAC Key */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, ctx->opad_tmp_keys_dma_addr, - ((ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE : - ctx->key_params.keylen), NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_KEY0); - set_cipher_mode(&desc[idx], DRV_CIPHER_CMAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], ctx->key_params.keylen); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - - /* Load MAC state */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, - CC_AES_BLOCK_SIZE, NS_BIT); - set_setup_mode(&desc[idx], SETUP_LOAD_STATE0); - set_cipher_mode(&desc[idx], DRV_CIPHER_CMAC); - set_cipher_config0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_key_size_aes(&desc[idx], ctx->key_params.keylen); - set_flow_mode(&desc[idx], S_DIN_to_AES); - idx++; - *seq_size = idx; -} - -static void cc_set_desc(struct ahash_req_ctx *areq_ctx, - struct cc_hash_ctx *ctx, unsigned int flow_mode, - struct cc_hw_desc desc[], bool is_not_last_data, - unsigned int *seq_size) -{ - unsigned int idx = *seq_size; - struct device *dev = drvdata_to_dev(ctx->drvdata); - - if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_DLLI) { - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - sg_dma_address(areq_ctx->curr_sg), - areq_ctx->curr_sg->length, NS_BIT); - set_flow_mode(&desc[idx], flow_mode); - idx++; - } else { - if (areq_ctx->data_dma_buf_type == CC_DMA_BUF_NULL) { - dev_dbg(dev, " NULL mode\n"); - /* nothing to build */ - return; - } - /* bypass */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_DLLI, - areq_ctx->mlli_params.mlli_dma_addr, - areq_ctx->mlli_params.mlli_len, NS_BIT); - set_dout_sram(&desc[idx], ctx->drvdata->mlli_sram_addr, - areq_ctx->mlli_params.mlli_len); - set_flow_mode(&desc[idx], BYPASS); - idx++; - /* process */ - hw_desc_init(&desc[idx]); - set_din_type(&desc[idx], DMA_MLLI, - ctx->drvdata->mlli_sram_addr, - areq_ctx->mlli_nents, NS_BIT); - set_flow_mode(&desc[idx], flow_mode); - idx++; - } - if (is_not_last_data) - set_din_not_last_indication(&desc[(idx - 1)]); - /* return updated desc sequence size */ - *seq_size = idx; -} - -static const void *cc_larval_digest(struct device *dev, u32 mode) -{ - switch (mode) { - case DRV_HASH_MD5: - return md5_init; - case DRV_HASH_SHA1: - return sha1_init; - case DRV_HASH_SHA224: - return sha224_init; - case DRV_HASH_SHA256: - return sha256_init; -#if (CC_DEV_SHA_MAX > 256) - case DRV_HASH_SHA384: - return sha384_init; - case DRV_HASH_SHA512: - return sha512_init; -#endif - default: - dev_err(dev, "Invalid hash mode (%d)\n", mode); - return md5_init; - } -} - -/*! - * Gets the address of the initial digest in SRAM - * according to the given hash mode - * - * \param drvdata - * \param mode The Hash mode. Supported modes: MD5/SHA1/SHA224/SHA256 - * - * \return u32 The address of the initial digest in SRAM - */ -cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode) -{ - struct cc_drvdata *_drvdata = (struct cc_drvdata *)drvdata; - struct cc_hash_handle *hash_handle = _drvdata->hash_handle; - struct device *dev = drvdata_to_dev(_drvdata); - - switch (mode) { - case DRV_HASH_NULL: - break; /*Ignore*/ - case DRV_HASH_MD5: - return (hash_handle->larval_digest_sram_addr); - case DRV_HASH_SHA1: - return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init)); - case DRV_HASH_SHA224: - return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init)); - case DRV_HASH_SHA256: - return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init)); -#if (CC_DEV_SHA_MAX > 256) - case DRV_HASH_SHA384: - return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init) + - sizeof(sha256_init)); - case DRV_HASH_SHA512: - return (hash_handle->larval_digest_sram_addr + - sizeof(md5_init) + - sizeof(sha1_init) + - sizeof(sha224_init) + - sizeof(sha256_init) + - sizeof(sha384_init)); -#endif - default: - dev_err(dev, "Invalid hash mode (%d)\n", mode); - } - - /*This is valid wrong value to avoid kernel crash*/ - return hash_handle->larval_digest_sram_addr; -} - -cc_sram_addr_t -cc_digest_len_addr(void *drvdata, u32 mode) -{ - struct cc_drvdata *_drvdata = (struct cc_drvdata *)drvdata; - struct cc_hash_handle *hash_handle = _drvdata->hash_handle; - cc_sram_addr_t digest_len_addr = hash_handle->digest_len_sram_addr; - - switch (mode) { - case DRV_HASH_SHA1: - case DRV_HASH_SHA224: - case DRV_HASH_SHA256: - case DRV_HASH_MD5: - return digest_len_addr; -#if (CC_DEV_SHA_MAX > 256) - case DRV_HASH_SHA384: - case DRV_HASH_SHA512: - return digest_len_addr + sizeof(digest_len_init); -#endif - default: - return digest_len_addr; /*to avoid kernel crash*/ - } -} - diff --git a/drivers/staging/ccree/cc_hash.h b/drivers/staging/ccree/cc_hash.h deleted file mode 100644 index aa42b8f4348d..000000000000 --- a/drivers/staging/ccree/cc_hash.h +++ /dev/null @@ -1,114 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -/* \file cc_hash.h - * ARM CryptoCell Hash Crypto API - */ - -#ifndef __CC_HASH_H__ -#define __CC_HASH_H__ - -#include "cc_buffer_mgr.h" - -#define HMAC_IPAD_CONST 0x36363636 -#define HMAC_OPAD_CONST 0x5C5C5C5C -#if (CC_DEV_SHA_MAX > 256) -#define HASH_LEN_SIZE 16 -#define CC_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE -#define CC_MAX_HASH_BLCK_SIZE SHA512_BLOCK_SIZE -#else -#define HASH_LEN_SIZE 8 -#define CC_MAX_HASH_DIGEST_SIZE SHA256_DIGEST_SIZE -#define CC_MAX_HASH_BLCK_SIZE SHA256_BLOCK_SIZE -#endif - -#define XCBC_MAC_K1_OFFSET 0 -#define XCBC_MAC_K2_OFFSET 16 -#define XCBC_MAC_K3_OFFSET 32 - -#define CC_EXPORT_MAGIC 0xC2EE1070U - -/* this struct was taken from drivers/crypto/nx/nx-aes-xcbc.c and it is used - * for xcbc/cmac statesize - */ -struct aeshash_state { - u8 state[AES_BLOCK_SIZE]; - unsigned int count; - u8 buffer[AES_BLOCK_SIZE]; -}; - -/* ahash state */ -struct ahash_req_ctx { - u8 buffers[2][CC_MAX_HASH_BLCK_SIZE] ____cacheline_aligned; - u8 digest_result_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned; - u8 digest_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned; - u8 opad_digest_buff[CC_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned; - u8 digest_bytes_len[HASH_LEN_SIZE] ____cacheline_aligned; - struct async_gen_req_ctx gen_ctx ____cacheline_aligned; - enum cc_req_dma_buf_type data_dma_buf_type; - dma_addr_t opad_digest_dma_addr; - dma_addr_t digest_buff_dma_addr; - dma_addr_t digest_bytes_len_dma_addr; - dma_addr_t digest_result_dma_addr; - u32 buf_cnt[2]; - u32 buff_index; - u32 xcbc_count; /* count xcbc update operatations */ - struct scatterlist buff_sg[2]; - struct scatterlist *curr_sg; - u32 in_nents; - u32 mlli_nents; - struct mlli_params mlli_params; -}; - -static inline u32 *cc_hash_buf_cnt(struct ahash_req_ctx *state) -{ - return &state->buf_cnt[state->buff_index]; -} - -static inline u8 *cc_hash_buf(struct ahash_req_ctx *state) -{ - return state->buffers[state->buff_index]; -} - -static inline u32 *cc_next_buf_cnt(struct ahash_req_ctx *state) -{ - return &state->buf_cnt[state->buff_index ^ 1]; -} - -static inline u8 *cc_next_buf(struct ahash_req_ctx *state) -{ - return state->buffers[state->buff_index ^ 1]; -} - -int cc_hash_alloc(struct cc_drvdata *drvdata); -int cc_init_hash_sram(struct cc_drvdata *drvdata); -int cc_hash_free(struct cc_drvdata *drvdata); - -/*! - * Gets the initial digest length - * - * \param drvdata - * \param mode The Hash mode. Supported modes: - * MD5/SHA1/SHA224/SHA256/SHA384/SHA512 - * - * \return u32 returns the address of the initial digest length in SRAM - */ -cc_sram_addr_t -cc_digest_len_addr(void *drvdata, u32 mode); - -/*! - * Gets the address of the initial digest in SRAM - * according to the given hash mode - * - * \param drvdata - * \param mode The Hash mode. Supported modes: - * MD5/SHA1/SHA224/SHA256/SHA384/SHA512 - * - * \return u32 The address of the initial digest in SRAM - */ -cc_sram_addr_t cc_larval_digest_addr(void *drvdata, u32 mode); - -void cc_hash_global_init(void); - -#endif /*__CC_HASH_H__*/ - diff --git a/drivers/staging/ccree/cc_host_regs.h b/drivers/staging/ccree/cc_host_regs.h deleted file mode 100644 index 69ef2fa0cb9b..000000000000 --- a/drivers/staging/ccree/cc_host_regs.h +++ /dev/null @@ -1,142 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef __CC_HOST_H__ -#define __CC_HOST_H__ - -// -------------------------------------- -// BLOCK: HOST_P -// -------------------------------------- -#define CC_HOST_IRR_REG_OFFSET 0xA00UL -#define CC_HOST_IRR_DSCRPTR_COMPLETION_LOW_INT_BIT_SHIFT 0x2UL -#define CC_HOST_IRR_DSCRPTR_COMPLETION_LOW_INT_BIT_SIZE 0x1UL -#define CC_HOST_IRR_AXI_ERR_INT_BIT_SHIFT 0x8UL -#define CC_HOST_IRR_AXI_ERR_INT_BIT_SIZE 0x1UL -#define CC_HOST_IRR_GPR0_BIT_SHIFT 0xBUL -#define CC_HOST_IRR_GPR0_BIT_SIZE 0x1UL -#define CC_HOST_IRR_DSCRPTR_WATERMARK_INT_BIT_SHIFT 0x13UL -#define CC_HOST_IRR_DSCRPTR_WATERMARK_INT_BIT_SIZE 0x1UL -#define CC_HOST_IRR_AXIM_COMP_INT_BIT_SHIFT 0x17UL -#define CC_HOST_IRR_AXIM_COMP_INT_BIT_SIZE 0x1UL -#define CC_HOST_IMR_REG_OFFSET 0xA04UL -#define CC_HOST_IMR_NOT_USED_MASK_BIT_SHIFT 0x1UL -#define CC_HOST_IMR_NOT_USED_MASK_BIT_SIZE 0x1UL -#define CC_HOST_IMR_DSCRPTR_COMPLETION_MASK_BIT_SHIFT 0x2UL -#define CC_HOST_IMR_DSCRPTR_COMPLETION_MASK_BIT_SIZE 0x1UL -#define CC_HOST_IMR_AXI_ERR_MASK_BIT_SHIFT 0x8UL -#define CC_HOST_IMR_AXI_ERR_MASK_BIT_SIZE 0x1UL -#define CC_HOST_IMR_GPR0_BIT_SHIFT 0xBUL -#define CC_HOST_IMR_GPR0_BIT_SIZE 0x1UL -#define CC_HOST_IMR_DSCRPTR_WATERMARK_MASK0_BIT_SHIFT 0x13UL -#define CC_HOST_IMR_DSCRPTR_WATERMARK_MASK0_BIT_SIZE 0x1UL -#define CC_HOST_IMR_AXIM_COMP_INT_MASK_BIT_SHIFT 0x17UL -#define CC_HOST_IMR_AXIM_COMP_INT_MASK_BIT_SIZE 0x1UL -#define CC_HOST_ICR_REG_OFFSET 0xA08UL -#define CC_HOST_ICR_DSCRPTR_COMPLETION_BIT_SHIFT 0x2UL -#define CC_HOST_ICR_DSCRPTR_COMPLETION_BIT_SIZE 0x1UL -#define CC_HOST_ICR_AXI_ERR_CLEAR_BIT_SHIFT 0x8UL -#define CC_HOST_ICR_AXI_ERR_CLEAR_BIT_SIZE 0x1UL -#define CC_HOST_ICR_GPR_INT_CLEAR_BIT_SHIFT 0xBUL -#define CC_HOST_ICR_GPR_INT_CLEAR_BIT_SIZE 0x1UL -#define CC_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SHIFT 0x13UL -#define CC_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SIZE 0x1UL -#define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SHIFT 0x17UL -#define CC_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SIZE 0x1UL -#define CC_HOST_SIGNATURE_REG_OFFSET 0xA24UL -#define CC_HOST_SIGNATURE_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_SIGNATURE_VALUE_BIT_SIZE 0x20UL -#define CC_HOST_BOOT_REG_OFFSET 0xA28UL -#define CC_HOST_BOOT_SYNTHESIS_CONFIG_BIT_SHIFT 0x0UL -#define CC_HOST_BOOT_SYNTHESIS_CONFIG_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_LARGE_RKEK_LOCAL_BIT_SHIFT 0x1UL -#define CC_HOST_BOOT_LARGE_RKEK_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_HASH_IN_FUSES_LOCAL_BIT_SHIFT 0x2UL -#define CC_HOST_BOOT_HASH_IN_FUSES_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_EXT_MEM_SECURED_LOCAL_BIT_SHIFT 0x3UL -#define CC_HOST_BOOT_EXT_MEM_SECURED_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_RKEK_ECC_EXISTS_LOCAL_N_BIT_SHIFT 0x5UL -#define CC_HOST_BOOT_RKEK_ECC_EXISTS_LOCAL_N_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_SRAM_SIZE_LOCAL_BIT_SHIFT 0x6UL -#define CC_HOST_BOOT_SRAM_SIZE_LOCAL_BIT_SIZE 0x3UL -#define CC_HOST_BOOT_DSCRPTR_EXISTS_LOCAL_BIT_SHIFT 0x9UL -#define CC_HOST_BOOT_DSCRPTR_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_PAU_EXISTS_LOCAL_BIT_SHIFT 0xAUL -#define CC_HOST_BOOT_PAU_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_RNG_EXISTS_LOCAL_BIT_SHIFT 0xBUL -#define CC_HOST_BOOT_RNG_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_PKA_EXISTS_LOCAL_BIT_SHIFT 0xCUL -#define CC_HOST_BOOT_PKA_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_RC4_EXISTS_LOCAL_BIT_SHIFT 0xDUL -#define CC_HOST_BOOT_RC4_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_SHA_512_PRSNT_LOCAL_BIT_SHIFT 0xEUL -#define CC_HOST_BOOT_SHA_512_PRSNT_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_SHA_256_PRSNT_LOCAL_BIT_SHIFT 0xFUL -#define CC_HOST_BOOT_SHA_256_PRSNT_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_MD5_PRSNT_LOCAL_BIT_SHIFT 0x10UL -#define CC_HOST_BOOT_MD5_PRSNT_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_HASH_EXISTS_LOCAL_BIT_SHIFT 0x11UL -#define CC_HOST_BOOT_HASH_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_C2_EXISTS_LOCAL_BIT_SHIFT 0x12UL -#define CC_HOST_BOOT_C2_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_DES_EXISTS_LOCAL_BIT_SHIFT 0x13UL -#define CC_HOST_BOOT_DES_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_AES_XCBC_MAC_EXISTS_LOCAL_BIT_SHIFT 0x14UL -#define CC_HOST_BOOT_AES_XCBC_MAC_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_AES_CMAC_EXISTS_LOCAL_BIT_SHIFT 0x15UL -#define CC_HOST_BOOT_AES_CMAC_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_AES_CCM_EXISTS_LOCAL_BIT_SHIFT 0x16UL -#define CC_HOST_BOOT_AES_CCM_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_AES_XEX_HW_T_CALC_LOCAL_BIT_SHIFT 0x17UL -#define CC_HOST_BOOT_AES_XEX_HW_T_CALC_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_AES_XEX_EXISTS_LOCAL_BIT_SHIFT 0x18UL -#define CC_HOST_BOOT_AES_XEX_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_CTR_EXISTS_LOCAL_BIT_SHIFT 0x19UL -#define CC_HOST_BOOT_CTR_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_AES_DIN_BYTE_RESOLUTION_LOCAL_BIT_SHIFT 0x1AUL -#define CC_HOST_BOOT_AES_DIN_BYTE_RESOLUTION_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_TUNNELING_ENB_LOCAL_BIT_SHIFT 0x1BUL -#define CC_HOST_BOOT_TUNNELING_ENB_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_SUPPORT_256_192_KEY_LOCAL_BIT_SHIFT 0x1CUL -#define CC_HOST_BOOT_SUPPORT_256_192_KEY_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_ONLY_ENCRYPT_LOCAL_BIT_SHIFT 0x1DUL -#define CC_HOST_BOOT_ONLY_ENCRYPT_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SHIFT 0x1EUL -#define CC_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SIZE 0x1UL -#define CC_HOST_VERSION_REG_OFFSET 0xA40UL -#define CC_HOST_VERSION_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_VERSION_VALUE_BIT_SIZE 0x20UL -#define CC_HOST_KFDE0_VALID_REG_OFFSET 0xA60UL -#define CC_HOST_KFDE0_VALID_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_KFDE0_VALID_VALUE_BIT_SIZE 0x1UL -#define CC_HOST_KFDE1_VALID_REG_OFFSET 0xA64UL -#define CC_HOST_KFDE1_VALID_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_KFDE1_VALID_VALUE_BIT_SIZE 0x1UL -#define CC_HOST_KFDE2_VALID_REG_OFFSET 0xA68UL -#define CC_HOST_KFDE2_VALID_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_KFDE2_VALID_VALUE_BIT_SIZE 0x1UL -#define CC_HOST_KFDE3_VALID_REG_OFFSET 0xA6CUL -#define CC_HOST_KFDE3_VALID_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_KFDE3_VALID_VALUE_BIT_SIZE 0x1UL -#define CC_HOST_GPR0_REG_OFFSET 0xA70UL -#define CC_HOST_GPR0_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_GPR0_VALUE_BIT_SIZE 0x20UL -#define CC_GPR_HOST_REG_OFFSET 0xA74UL -#define CC_GPR_HOST_VALUE_BIT_SHIFT 0x0UL -#define CC_GPR_HOST_VALUE_BIT_SIZE 0x20UL -#define CC_HOST_POWER_DOWN_EN_REG_OFFSET 0xA78UL -#define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SHIFT 0x0UL -#define CC_HOST_POWER_DOWN_EN_VALUE_BIT_SIZE 0x1UL -// -------------------------------------- -// BLOCK: HOST_SRAM -// -------------------------------------- -#define CC_SRAM_DATA_REG_OFFSET 0xF00UL -#define CC_SRAM_DATA_VALUE_BIT_SHIFT 0x0UL -#define CC_SRAM_DATA_VALUE_BIT_SIZE 0x20UL -#define CC_SRAM_ADDR_REG_OFFSET 0xF04UL -#define CC_SRAM_ADDR_VALUE_BIT_SHIFT 0x0UL -#define CC_SRAM_ADDR_VALUE_BIT_SIZE 0xFUL -#define CC_SRAM_DATA_READY_REG_OFFSET 0xF08UL -#define CC_SRAM_DATA_READY_VALUE_BIT_SHIFT 0x0UL -#define CC_SRAM_DATA_READY_VALUE_BIT_SIZE 0x1UL - -#endif //__CC_HOST_H__ diff --git a/drivers/staging/ccree/cc_hw_queue_defs.h b/drivers/staging/ccree/cc_hw_queue_defs.h deleted file mode 100644 index a79f28cec5ae..000000000000 --- a/drivers/staging/ccree/cc_hw_queue_defs.h +++ /dev/null @@ -1,590 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef __CC_HW_QUEUE_DEFS_H__ -#define __CC_HW_QUEUE_DEFS_H__ - -#include <linux/types.h> - -#include "cc_kernel_regs.h" -#include <linux/bitfield.h> - -/****************************************************************************** - * DEFINITIONS - ******************************************************************************/ - -#define HW_DESC_SIZE_WORDS 6 -/* Define max. available slots in HW queue */ -#define HW_QUEUE_SLOTS_MAX 15 - -#define CC_REG_LOW(word, name) \ - (CC_DSCRPTR_QUEUE_WORD ## word ## _ ## name ## _BIT_SHIFT) - -#define CC_REG_HIGH(word, name) \ - (CC_REG_LOW(word, name) + \ - CC_DSCRPTR_QUEUE_WORD ## word ## _ ## name ## _BIT_SIZE - 1) - -#define CC_GENMASK(word, name) \ - GENMASK(CC_REG_HIGH(word, name), CC_REG_LOW(word, name)) - -#define WORD0_VALUE CC_GENMASK(0, VALUE) -#define WORD1_DIN_CONST_VALUE CC_GENMASK(1, DIN_CONST_VALUE) -#define WORD1_DIN_DMA_MODE CC_GENMASK(1, DIN_DMA_MODE) -#define WORD1_DIN_SIZE CC_GENMASK(1, DIN_SIZE) -#define WORD1_NOT_LAST CC_GENMASK(1, NOT_LAST) -#define WORD1_NS_BIT CC_GENMASK(1, NS_BIT) -#define WORD2_VALUE CC_GENMASK(2, VALUE) -#define WORD3_DOUT_DMA_MODE CC_GENMASK(3, DOUT_DMA_MODE) -#define WORD3_DOUT_LAST_IND CC_GENMASK(3, DOUT_LAST_IND) -#define WORD3_DOUT_SIZE CC_GENMASK(3, DOUT_SIZE) -#define WORD3_HASH_XOR_BIT CC_GENMASK(3, HASH_XOR_BIT) -#define WORD3_NS_BIT CC_GENMASK(3, NS_BIT) -#define WORD3_QUEUE_LAST_IND CC_GENMASK(3, QUEUE_LAST_IND) -#define WORD4_ACK_NEEDED CC_GENMASK(4, ACK_NEEDED) -#define WORD4_AES_SEL_N_HASH CC_GENMASK(4, AES_SEL_N_HASH) -#define WORD4_BYTES_SWAP CC_GENMASK(4, BYTES_SWAP) -#define WORD4_CIPHER_CONF0 CC_GENMASK(4, CIPHER_CONF0) -#define WORD4_CIPHER_CONF1 CC_GENMASK(4, CIPHER_CONF1) -#define WORD4_CIPHER_CONF2 CC_GENMASK(4, CIPHER_CONF2) -#define WORD4_CIPHER_DO CC_GENMASK(4, CIPHER_DO) -#define WORD4_CIPHER_MODE CC_GENMASK(4, CIPHER_MODE) -#define WORD4_CMAC_SIZE0 CC_GENMASK(4, CMAC_SIZE0) -#define WORD4_DATA_FLOW_MODE CC_GENMASK(4, DATA_FLOW_MODE) -#define WORD4_KEY_SIZE CC_GENMASK(4, KEY_SIZE) -#define WORD4_SETUP_OPERATION CC_GENMASK(4, SETUP_OPERATION) -#define WORD5_DIN_ADDR_HIGH CC_GENMASK(5, DIN_ADDR_HIGH) -#define WORD5_DOUT_ADDR_HIGH CC_GENMASK(5, DOUT_ADDR_HIGH) - -/****************************************************************************** - * TYPE DEFINITIONS - ******************************************************************************/ - -struct cc_hw_desc { - union { - u32 word[HW_DESC_SIZE_WORDS]; - u16 hword[HW_DESC_SIZE_WORDS * 2]; - }; -}; - -enum cc_axi_sec { - AXI_SECURE = 0, - AXI_NOT_SECURE = 1 -}; - -enum cc_desc_direction { - DESC_DIRECTION_ILLEGAL = -1, - DESC_DIRECTION_ENCRYPT_ENCRYPT = 0, - DESC_DIRECTION_DECRYPT_DECRYPT = 1, - DESC_DIRECTION_DECRYPT_ENCRYPT = 3, - DESC_DIRECTION_END = S32_MAX, -}; - -enum cc_dma_mode { - DMA_MODE_NULL = -1, - NO_DMA = 0, - DMA_SRAM = 1, - DMA_DLLI = 2, - DMA_MLLI = 3, - DMA_MODE_END = S32_MAX, -}; - -enum cc_flow_mode { - FLOW_MODE_NULL = -1, - /* data flows */ - BYPASS = 0, - DIN_AES_DOUT = 1, - AES_to_HASH = 2, - AES_and_HASH = 3, - DIN_DES_DOUT = 4, - DES_to_HASH = 5, - DES_and_HASH = 6, - DIN_HASH = 7, - DIN_HASH_and_BYPASS = 8, - AESMAC_and_BYPASS = 9, - AES_to_HASH_and_DOUT = 10, - DIN_RC4_DOUT = 11, - DES_to_HASH_and_DOUT = 12, - AES_to_AES_to_HASH_and_DOUT = 13, - AES_to_AES_to_HASH = 14, - AES_to_HASH_and_AES = 15, - DIN_AES_AESMAC = 17, - HASH_to_DOUT = 18, - /* setup flows */ - S_DIN_to_AES = 32, - S_DIN_to_AES2 = 33, - S_DIN_to_DES = 34, - S_DIN_to_RC4 = 35, - S_DIN_to_HASH = 37, - S_AES_to_DOUT = 38, - S_AES2_to_DOUT = 39, - S_RC4_to_DOUT = 41, - S_DES_to_DOUT = 42, - S_HASH_to_DOUT = 43, - SET_FLOW_ID = 44, - FLOW_MODE_END = S32_MAX, -}; - -enum cc_tunnel_op { - TUNNEL_OP_INVALID = -1, - TUNNEL_OFF = 0, - TUNNEL_ON = 1, - TUNNEL_OP_END = S32_MAX, -}; - -enum cc_setup_op { - SETUP_LOAD_NOP = 0, - SETUP_LOAD_STATE0 = 1, - SETUP_LOAD_STATE1 = 2, - SETUP_LOAD_STATE2 = 3, - SETUP_LOAD_KEY0 = 4, - SETUP_LOAD_XEX_KEY = 5, - SETUP_WRITE_STATE0 = 8, - SETUP_WRITE_STATE1 = 9, - SETUP_WRITE_STATE2 = 10, - SETUP_WRITE_STATE3 = 11, - SETUP_OP_END = S32_MAX, -}; - -enum cc_aes_mac_selector { - AES_SK = 1, - AES_CMAC_INIT = 2, - AES_CMAC_SIZE0 = 3, - AES_MAC_END = S32_MAX, -}; - -#define HW_KEY_MASK_CIPHER_DO 0x3 -#define HW_KEY_SHIFT_CIPHER_CFG2 2 - -/* HwCryptoKey[1:0] is mapped to cipher_do[1:0] */ -/* HwCryptoKey[2:3] is mapped to cipher_config2[1:0] */ -enum cc_hw_crypto_key { - USER_KEY = 0, /* 0x0000 */ - ROOT_KEY = 1, /* 0x0001 */ - PROVISIONING_KEY = 2, /* 0x0010 */ /* ==KCP */ - SESSION_KEY = 3, /* 0x0011 */ - RESERVED_KEY = 4, /* NA */ - PLATFORM_KEY = 5, /* 0x0101 */ - CUSTOMER_KEY = 6, /* 0x0110 */ - KFDE0_KEY = 7, /* 0x0111 */ - KFDE1_KEY = 9, /* 0x1001 */ - KFDE2_KEY = 10, /* 0x1010 */ - KFDE3_KEY = 11, /* 0x1011 */ - END_OF_KEYS = S32_MAX, -}; - -enum cc_hw_aes_key_size { - AES_128_KEY = 0, - AES_192_KEY = 1, - AES_256_KEY = 2, - END_OF_AES_KEYS = S32_MAX, -}; - -enum cc_hw_des_key_size { - DES_ONE_KEY = 0, - DES_TWO_KEYS = 1, - DES_THREE_KEYS = 2, - END_OF_DES_KEYS = S32_MAX, -}; - -enum cc_hash_conf_pad { - HASH_PADDING_DISABLED = 0, - HASH_PADDING_ENABLED = 1, - HASH_DIGEST_RESULT_LITTLE_ENDIAN = 2, - HASH_CONFIG1_PADDING_RESERVE32 = S32_MAX, -}; - -enum cc_hash_cipher_pad { - DO_NOT_PAD = 0, - DO_PAD = 1, - HASH_CIPHER_DO_PADDING_RESERVE32 = S32_MAX, -}; - -/*****************************/ -/* Descriptor packing macros */ -/*****************************/ - -/* - * Init a HW descriptor struct - * @pdesc: pointer HW descriptor struct - */ -static inline void hw_desc_init(struct cc_hw_desc *pdesc) -{ - memset(pdesc, 0, sizeof(struct cc_hw_desc)); -} - -/* - * Indicates the end of current HW descriptors flow and release the HW engines. - * - * @pdesc: pointer HW descriptor struct - */ -static inline void set_queue_last_ind(struct cc_hw_desc *pdesc) -{ - pdesc->word[3] |= FIELD_PREP(WORD3_QUEUE_LAST_IND, 1); -} - -/* - * Set the DIN field of a HW descriptors - * - * @pdesc: pointer HW descriptor struct - * @dma_mode: dmaMode The DMA mode: NO_DMA, SRAM, DLLI, MLLI, CONSTANT - * @addr: dinAdr DIN address - * @size: Data size in bytes - * @axi_sec: AXI secure bit - */ -static inline void set_din_type(struct cc_hw_desc *pdesc, - enum cc_dma_mode dma_mode, dma_addr_t addr, - u32 size, enum cc_axi_sec axi_sec) -{ - pdesc->word[0] = (u32)addr; -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - pdesc->word[5] |= FIELD_PREP(WORD5_DIN_ADDR_HIGH, ((u16)(addr >> 32))); -#endif - pdesc->word[1] |= FIELD_PREP(WORD1_DIN_DMA_MODE, dma_mode) | - FIELD_PREP(WORD1_DIN_SIZE, size) | - FIELD_PREP(WORD1_NS_BIT, axi_sec); -} - -/* - * Set the DIN field of a HW descriptors to NO DMA mode. - * Used for NOP descriptor, register patches and other special modes. - * - * @pdesc: pointer HW descriptor struct - * @addr: DIN address - * @size: Data size in bytes - */ -static inline void set_din_no_dma(struct cc_hw_desc *pdesc, u32 addr, u32 size) -{ - pdesc->word[0] = addr; - pdesc->word[1] |= FIELD_PREP(WORD1_DIN_SIZE, size); -} - -/* - * Set the DIN field of a HW descriptors to SRAM mode. - * Note: No need to check SRAM alignment since host requests do not use SRAM and - * adaptor will enforce alignment check. - * - * @pdesc: pointer HW descriptor struct - * @addr: DIN address - * @size Data size in bytes - */ -static inline void set_din_sram(struct cc_hw_desc *pdesc, dma_addr_t addr, - u32 size) -{ - pdesc->word[0] = (u32)addr; - pdesc->word[1] |= FIELD_PREP(WORD1_DIN_SIZE, size) | - FIELD_PREP(WORD1_DIN_DMA_MODE, DMA_SRAM); -} - -/* - * Set the DIN field of a HW descriptors to CONST mode - * - * @pdesc: pointer HW descriptor struct - * @val: DIN const value - * @size: Data size in bytes - */ -static inline void set_din_const(struct cc_hw_desc *pdesc, u32 val, u32 size) -{ - pdesc->word[0] = val; - pdesc->word[1] |= FIELD_PREP(WORD1_DIN_CONST_VALUE, 1) | - FIELD_PREP(WORD1_DIN_DMA_MODE, DMA_SRAM) | - FIELD_PREP(WORD1_DIN_SIZE, size); -} - -/* - * Set the DIN not last input data indicator - * - * @pdesc: pointer HW descriptor struct - */ -static inline void set_din_not_last_indication(struct cc_hw_desc *pdesc) -{ - pdesc->word[1] |= FIELD_PREP(WORD1_NOT_LAST, 1); -} - -/* - * Set the DOUT field of a HW descriptors - * - * @pdesc: pointer HW descriptor struct - * @dma_mode: The DMA mode: NO_DMA, SRAM, DLLI, MLLI, CONSTANT - * @addr: DOUT address - * @size: Data size in bytes - * @axi_sec: AXI secure bit - */ -static inline void set_dout_type(struct cc_hw_desc *pdesc, - enum cc_dma_mode dma_mode, dma_addr_t addr, - u32 size, enum cc_axi_sec axi_sec) -{ - pdesc->word[2] = (u32)addr; -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - pdesc->word[5] |= FIELD_PREP(WORD5_DOUT_ADDR_HIGH, ((u16)(addr >> 32))); -#endif - pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_DMA_MODE, dma_mode) | - FIELD_PREP(WORD3_DOUT_SIZE, size) | - FIELD_PREP(WORD3_NS_BIT, axi_sec); -} - -/* - * Set the DOUT field of a HW descriptors to DLLI type - * The LAST INDICATION is provided by the user - * - * @pdesc pointer HW descriptor struct - * @addr: DOUT address - * @size: Data size in bytes - * @last_ind: The last indication bit - * @axi_sec: AXI secure bit - */ -static inline void set_dout_dlli(struct cc_hw_desc *pdesc, dma_addr_t addr, - u32 size, enum cc_axi_sec axi_sec, - u32 last_ind) -{ - set_dout_type(pdesc, DMA_DLLI, addr, size, axi_sec); - pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_LAST_IND, last_ind); -} - -/* - * Set the DOUT field of a HW descriptors to DLLI type - * The LAST INDICATION is provided by the user - * - * @pdesc: pointer HW descriptor struct - * @addr: DOUT address - * @size: Data size in bytes - * @last_ind: The last indication bit - * @axi_sec: AXI secure bit - */ -static inline void set_dout_mlli(struct cc_hw_desc *pdesc, dma_addr_t addr, - u32 size, enum cc_axi_sec axi_sec, - bool last_ind) -{ - set_dout_type(pdesc, DMA_MLLI, addr, size, axi_sec); - pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_LAST_IND, last_ind); -} - -/* - * Set the DOUT field of a HW descriptors to NO DMA mode. - * Used for NOP descriptor, register patches and other special modes. - * - * @pdesc: pointer HW descriptor struct - * @addr: DOUT address - * @size: Data size in bytes - * @write_enable: Enables a write operation to a register - */ -static inline void set_dout_no_dma(struct cc_hw_desc *pdesc, u32 addr, - u32 size, bool write_enable) -{ - pdesc->word[2] = addr; - pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_SIZE, size) | - FIELD_PREP(WORD3_DOUT_LAST_IND, write_enable); -} - -/* - * Set the word for the XOR operation. - * - * @pdesc: pointer HW descriptor struct - * @val: xor data value - */ -static inline void set_xor_val(struct cc_hw_desc *pdesc, u32 val) -{ - pdesc->word[2] = val; -} - -/* - * Sets the XOR indicator bit in the descriptor - * - * @pdesc: pointer HW descriptor struct - */ -static inline void set_xor_active(struct cc_hw_desc *pdesc) -{ - pdesc->word[3] |= FIELD_PREP(WORD3_HASH_XOR_BIT, 1); -} - -/* - * Select the AES engine instead of HASH engine when setting up combined mode - * with AES XCBC MAC - * - * @pdesc: pointer HW descriptor struct - */ -static inline void set_aes_not_hash_mode(struct cc_hw_desc *pdesc) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_AES_SEL_N_HASH, 1); -} - -/* - * Set the DOUT field of a HW descriptors to SRAM mode - * Note: No need to check SRAM alignment since host requests do not use SRAM and - * adaptor will enforce alignment check. - * - * @pdesc: pointer HW descriptor struct - * @addr: DOUT address - * @size: Data size in bytes - */ -static inline void set_dout_sram(struct cc_hw_desc *pdesc, u32 addr, u32 size) -{ - pdesc->word[2] = addr; - pdesc->word[3] |= FIELD_PREP(WORD3_DOUT_DMA_MODE, DMA_SRAM) | - FIELD_PREP(WORD3_DOUT_SIZE, size); -} - -/* - * Sets the data unit size for XEX mode in data_out_addr[15:0] - * - * @pdesc: pDesc pointer HW descriptor struct - * @size: data unit size for XEX mode - */ -static inline void set_xex_data_unit_size(struct cc_hw_desc *pdesc, u32 size) -{ - pdesc->word[2] = size; -} - -/* - * Set the number of rounds for Multi2 in data_out_addr[15:0] - * - * @pdesc: pointer HW descriptor struct - * @num: number of rounds for Multi2 - */ -static inline void set_multi2_num_rounds(struct cc_hw_desc *pdesc, u32 num) -{ - pdesc->word[2] = num; -} - -/* - * Set the flow mode. - * - * @pdesc: pointer HW descriptor struct - * @mode: Any one of the modes defined in [CC7x-DESC] - */ -static inline void set_flow_mode(struct cc_hw_desc *pdesc, - enum cc_flow_mode mode) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_DATA_FLOW_MODE, mode); -} - -/* - * Set the cipher mode. - * - * @pdesc: pointer HW descriptor struct - * @mode: Any one of the modes defined in [CC7x-DESC] - */ -static inline void set_cipher_mode(struct cc_hw_desc *pdesc, - enum drv_cipher_mode mode) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_MODE, mode); -} - -/* - * Set the cipher configuration fields. - * - * @pdesc: pointer HW descriptor struct - * @mode: Any one of the modes defined in [CC7x-DESC] - */ -static inline void set_cipher_config0(struct cc_hw_desc *pdesc, - enum drv_crypto_direction mode) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_CONF0, mode); -} - -/* - * Set the cipher configuration fields. - * - * @pdesc: pointer HW descriptor struct - * @config: Any one of the modes defined in [CC7x-DESC] - */ -static inline void set_cipher_config1(struct cc_hw_desc *pdesc, - enum cc_hash_conf_pad config) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_CONF1, config); -} - -/* - * Set HW key configuration fields. - * - * @pdesc: pointer HW descriptor struct - * @hw_key: The HW key slot asdefined in enum cc_hw_crypto_key - */ -static inline void set_hw_crypto_key(struct cc_hw_desc *pdesc, - enum cc_hw_crypto_key hw_key) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_DO, - (hw_key & HW_KEY_MASK_CIPHER_DO)) | - FIELD_PREP(WORD4_CIPHER_CONF2, - (hw_key >> HW_KEY_SHIFT_CIPHER_CFG2)); -} - -/* - * Set byte order of all setup-finalize descriptors. - * - * @pdesc: pointer HW descriptor struct - * @config: Any one of the modes defined in [CC7x-DESC] - */ -static inline void set_bytes_swap(struct cc_hw_desc *pdesc, bool config) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_BYTES_SWAP, config); -} - -/* - * Set CMAC_SIZE0 mode. - * - * @pdesc: pointer HW descriptor struct - */ -static inline void set_cmac_size0_mode(struct cc_hw_desc *pdesc) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_CMAC_SIZE0, 1); -} - -/* - * Set key size descriptor field. - * - * @pdesc: pointer HW descriptor struct - * @size: key size in bytes (NOT size code) - */ -static inline void set_key_size(struct cc_hw_desc *pdesc, u32 size) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_KEY_SIZE, size); -} - -/* - * Set AES key size. - * - * @pdesc: pointer HW descriptor struct - * @size: key size in bytes (NOT size code) - */ -static inline void set_key_size_aes(struct cc_hw_desc *pdesc, u32 size) -{ - set_key_size(pdesc, ((size >> 3) - 2)); -} - -/* - * Set DES key size. - * - * @pdesc: pointer HW descriptor struct - * @size: key size in bytes (NOT size code) - */ -static inline void set_key_size_des(struct cc_hw_desc *pdesc, u32 size) -{ - set_key_size(pdesc, ((size >> 3) - 1)); -} - -/* - * Set the descriptor setup mode - * - * @pdesc: pointer HW descriptor struct - * @mode: Any one of the setup modes defined in [CC7x-DESC] - */ -static inline void set_setup_mode(struct cc_hw_desc *pdesc, - enum cc_setup_op mode) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_SETUP_OPERATION, mode); -} - -/* - * Set the descriptor cipher DO - * - * @pdesc: pointer HW descriptor struct - * @config: Any one of the cipher do defined in [CC7x-DESC] - */ -static inline void set_cipher_do(struct cc_hw_desc *pdesc, - enum cc_hash_cipher_pad config) -{ - pdesc->word[4] |= FIELD_PREP(WORD4_CIPHER_DO, - (config & HW_KEY_MASK_CIPHER_DO)); -} - -#endif /*__CC_HW_QUEUE_DEFS_H__*/ diff --git a/drivers/staging/ccree/cc_ivgen.c b/drivers/staging/ccree/cc_ivgen.c deleted file mode 100644 index c47f419b277b..000000000000 --- a/drivers/staging/ccree/cc_ivgen.c +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <crypto/ctr.h> -#include "cc_driver.h" -#include "cc_ivgen.h" -#include "cc_request_mgr.h" -#include "cc_sram_mgr.h" -#include "cc_buffer_mgr.h" - -/* The max. size of pool *MUST* be <= SRAM total size */ -#define CC_IVPOOL_SIZE 1024 -/* The first 32B fraction of pool are dedicated to the - * next encryption "key" & "IV" for pool regeneration - */ -#define CC_IVPOOL_META_SIZE (CC_AES_IV_SIZE + AES_KEYSIZE_128) -#define CC_IVPOOL_GEN_SEQ_LEN 4 - -/** - * struct cc_ivgen_ctx -IV pool generation context - * @pool: the start address of the iv-pool resides in internal RAM - * @ctr_key_dma: address of pool's encryption key material in internal RAM - * @ctr_iv_dma: address of pool's counter iv in internal RAM - * @next_iv_ofs: the offset to the next available IV in pool - * @pool_meta: virt. address of the initial enc. key/IV - * @pool_meta_dma: phys. address of the initial enc. key/IV - */ -struct cc_ivgen_ctx { - cc_sram_addr_t pool; - cc_sram_addr_t ctr_key; - cc_sram_addr_t ctr_iv; - u32 next_iv_ofs; - u8 *pool_meta; - dma_addr_t pool_meta_dma; -}; - -/*! - * Generates CC_IVPOOL_SIZE of random bytes by - * encrypting 0's using AES128-CTR. - * - * \param ivgen iv-pool context - * \param iv_seq IN/OUT array to the descriptors sequence - * \param iv_seq_len IN/OUT pointer to the sequence length - */ -static int cc_gen_iv_pool(struct cc_ivgen_ctx *ivgen_ctx, - struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len) -{ - unsigned int idx = *iv_seq_len; - - if ((*iv_seq_len + CC_IVPOOL_GEN_SEQ_LEN) > CC_IVPOOL_SEQ_LEN) { - /* The sequence will be longer than allowed */ - return -EINVAL; - } - /* Setup key */ - hw_desc_init(&iv_seq[idx]); - set_din_sram(&iv_seq[idx], ivgen_ctx->ctr_key, AES_KEYSIZE_128); - set_setup_mode(&iv_seq[idx], SETUP_LOAD_KEY0); - set_cipher_config0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&iv_seq[idx], S_DIN_to_AES); - set_key_size_aes(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE); - set_cipher_mode(&iv_seq[idx], DRV_CIPHER_CTR); - idx++; - - /* Setup cipher state */ - hw_desc_init(&iv_seq[idx]); - set_din_sram(&iv_seq[idx], ivgen_ctx->ctr_iv, CC_AES_IV_SIZE); - set_cipher_config0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT); - set_flow_mode(&iv_seq[idx], S_DIN_to_AES); - set_setup_mode(&iv_seq[idx], SETUP_LOAD_STATE1); - set_key_size_aes(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE); - set_cipher_mode(&iv_seq[idx], DRV_CIPHER_CTR); - idx++; - - /* Perform dummy encrypt to skip first block */ - hw_desc_init(&iv_seq[idx]); - set_din_const(&iv_seq[idx], 0, CC_AES_IV_SIZE); - set_dout_sram(&iv_seq[idx], ivgen_ctx->pool, CC_AES_IV_SIZE); - set_flow_mode(&iv_seq[idx], DIN_AES_DOUT); - idx++; - - /* Generate IV pool */ - hw_desc_init(&iv_seq[idx]); - set_din_const(&iv_seq[idx], 0, CC_IVPOOL_SIZE); - set_dout_sram(&iv_seq[idx], ivgen_ctx->pool, CC_IVPOOL_SIZE); - set_flow_mode(&iv_seq[idx], DIN_AES_DOUT); - idx++; - - *iv_seq_len = idx; /* Update sequence length */ - - /* queue ordering assures pool readiness */ - ivgen_ctx->next_iv_ofs = CC_IVPOOL_META_SIZE; - - return 0; -} - -/*! - * Generates the initial pool in SRAM. - * This function should be invoked when resuming DX driver. - * - * \param drvdata - * - * \return int Zero for success, negative value otherwise. - */ -int cc_init_iv_sram(struct cc_drvdata *drvdata) -{ - struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle; - struct cc_hw_desc iv_seq[CC_IVPOOL_SEQ_LEN]; - unsigned int iv_seq_len = 0; - int rc; - - /* Generate initial enc. key/iv */ - get_random_bytes(ivgen_ctx->pool_meta, CC_IVPOOL_META_SIZE); - - /* The first 32B reserved for the enc. Key/IV */ - ivgen_ctx->ctr_key = ivgen_ctx->pool; - ivgen_ctx->ctr_iv = ivgen_ctx->pool + AES_KEYSIZE_128; - - /* Copy initial enc. key and IV to SRAM at a single descriptor */ - hw_desc_init(&iv_seq[iv_seq_len]); - set_din_type(&iv_seq[iv_seq_len], DMA_DLLI, ivgen_ctx->pool_meta_dma, - CC_IVPOOL_META_SIZE, NS_BIT); - set_dout_sram(&iv_seq[iv_seq_len], ivgen_ctx->pool, - CC_IVPOOL_META_SIZE); - set_flow_mode(&iv_seq[iv_seq_len], BYPASS); - iv_seq_len++; - - /* Generate initial pool */ - rc = cc_gen_iv_pool(ivgen_ctx, iv_seq, &iv_seq_len); - if (rc) - return rc; - - /* Fire-and-forget */ - return send_request_init(drvdata, iv_seq, iv_seq_len); -} - -/*! - * Free iv-pool and ivgen context. - * - * \param drvdata - */ -void cc_ivgen_fini(struct cc_drvdata *drvdata) -{ - struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle; - struct device *device = &drvdata->plat_dev->dev; - - if (!ivgen_ctx) - return; - - if (ivgen_ctx->pool_meta) { - memset(ivgen_ctx->pool_meta, 0, CC_IVPOOL_META_SIZE); - dma_free_coherent(device, CC_IVPOOL_META_SIZE, - ivgen_ctx->pool_meta, - ivgen_ctx->pool_meta_dma); - } - - ivgen_ctx->pool = NULL_SRAM_ADDR; - - /* release "this" context */ - kfree(ivgen_ctx); -} - -/*! - * Allocates iv-pool and maps resources. - * This function generates the first IV pool. - * - * \param drvdata Driver's private context - * - * \return int Zero for success, negative value otherwise. - */ -int cc_ivgen_init(struct cc_drvdata *drvdata) -{ - struct cc_ivgen_ctx *ivgen_ctx; - struct device *device = &drvdata->plat_dev->dev; - int rc; - - /* Allocate "this" context */ - ivgen_ctx = kzalloc(sizeof(*ivgen_ctx), GFP_KERNEL); - if (!ivgen_ctx) - return -ENOMEM; - - drvdata->ivgen_handle = ivgen_ctx; - - /* Allocate pool's header for initial enc. key/IV */ - ivgen_ctx->pool_meta = dma_alloc_coherent(device, CC_IVPOOL_META_SIZE, - &ivgen_ctx->pool_meta_dma, - GFP_KERNEL); - if (!ivgen_ctx->pool_meta) { - dev_err(device, "Not enough memory to allocate DMA of pool_meta (%u B)\n", - CC_IVPOOL_META_SIZE); - rc = -ENOMEM; - goto out; - } - /* Allocate IV pool in SRAM */ - ivgen_ctx->pool = cc_sram_alloc(drvdata, CC_IVPOOL_SIZE); - if (ivgen_ctx->pool == NULL_SRAM_ADDR) { - dev_err(device, "SRAM pool exhausted\n"); - rc = -ENOMEM; - goto out; - } - - return cc_init_iv_sram(drvdata); - -out: - cc_ivgen_fini(drvdata); - return rc; -} - -/*! - * Acquires 16 Bytes IV from the iv-pool - * - * \param drvdata Driver private context - * \param iv_out_dma Array of physical IV out addresses - * \param iv_out_dma_len Length of iv_out_dma array (additional elements - * of iv_out_dma array are ignore) - * \param iv_out_size May be 8 or 16 bytes long - * \param iv_seq IN/OUT array to the descriptors sequence - * \param iv_seq_len IN/OUT pointer to the sequence length - * - * \return int Zero for success, negative value otherwise. - */ -int cc_get_iv(struct cc_drvdata *drvdata, dma_addr_t iv_out_dma[], - unsigned int iv_out_dma_len, unsigned int iv_out_size, - struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len) -{ - struct cc_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle; - unsigned int idx = *iv_seq_len; - struct device *dev = drvdata_to_dev(drvdata); - unsigned int t; - - if (iv_out_size != CC_AES_IV_SIZE && - iv_out_size != CTR_RFC3686_IV_SIZE) { - return -EINVAL; - } - if ((iv_out_dma_len + 1) > CC_IVPOOL_SEQ_LEN) { - /* The sequence will be longer than allowed */ - return -EINVAL; - } - - /* check that number of generated IV is limited to max dma address - * iv buffer size - */ - if (iv_out_dma_len > CC_MAX_IVGEN_DMA_ADDRESSES) { - /* The sequence will be longer than allowed */ - return -EINVAL; - } - - for (t = 0; t < iv_out_dma_len; t++) { - /* Acquire IV from pool */ - hw_desc_init(&iv_seq[idx]); - set_din_sram(&iv_seq[idx], (ivgen_ctx->pool + - ivgen_ctx->next_iv_ofs), - iv_out_size); - set_dout_dlli(&iv_seq[idx], iv_out_dma[t], iv_out_size, - NS_BIT, 0); - set_flow_mode(&iv_seq[idx], BYPASS); - idx++; - } - - /* Bypass operation is proceeded by crypto sequence, hence must - * assure bypass-write-transaction by a memory barrier - */ - hw_desc_init(&iv_seq[idx]); - set_din_no_dma(&iv_seq[idx], 0, 0xfffff0); - set_dout_no_dma(&iv_seq[idx], 0, 0, 1); - idx++; - - *iv_seq_len = idx; /* update seq length */ - - /* Update iv index */ - ivgen_ctx->next_iv_ofs += iv_out_size; - - if ((CC_IVPOOL_SIZE - ivgen_ctx->next_iv_ofs) < CC_AES_IV_SIZE) { - dev_dbg(dev, "Pool exhausted, regenerating iv-pool\n"); - /* pool is drained -regenerate it! */ - return cc_gen_iv_pool(ivgen_ctx, iv_seq, iv_seq_len); - } - - return 0; -} - diff --git a/drivers/staging/ccree/cc_ivgen.h b/drivers/staging/ccree/cc_ivgen.h deleted file mode 100644 index b6ac16903dda..000000000000 --- a/drivers/staging/ccree/cc_ivgen.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef __CC_IVGEN_H__ -#define __CC_IVGEN_H__ - -#include "cc_hw_queue_defs.h" - -#define CC_IVPOOL_SEQ_LEN 8 - -/*! - * Allocates iv-pool and maps resources. - * This function generates the first IV pool. - * - * \param drvdata Driver's private context - * - * \return int Zero for success, negative value otherwise. - */ -int cc_ivgen_init(struct cc_drvdata *drvdata); - -/*! - * Free iv-pool and ivgen context. - * - * \param drvdata - */ -void cc_ivgen_fini(struct cc_drvdata *drvdata); - -/*! - * Generates the initial pool in SRAM. - * This function should be invoked when resuming DX driver. - * - * \param drvdata - * - * \return int Zero for success, negative value otherwise. - */ -int cc_init_iv_sram(struct cc_drvdata *drvdata); - -/*! - * Acquires 16 Bytes IV from the iv-pool - * - * \param drvdata Driver private context - * \param iv_out_dma Array of physical IV out addresses - * \param iv_out_dma_len Length of iv_out_dma array (additional elements of - * iv_out_dma array are ignore) - * \param iv_out_size May be 8 or 16 bytes long - * \param iv_seq IN/OUT array to the descriptors sequence - * \param iv_seq_len IN/OUT pointer to the sequence length - * - * \return int Zero for success, negative value otherwise. - */ -int cc_get_iv(struct cc_drvdata *drvdata, dma_addr_t iv_out_dma[], - unsigned int iv_out_dma_len, unsigned int iv_out_size, - struct cc_hw_desc iv_seq[], unsigned int *iv_seq_len); - -#endif /*__CC_IVGEN_H__*/ diff --git a/drivers/staging/ccree/cc_kernel_regs.h b/drivers/staging/ccree/cc_kernel_regs.h deleted file mode 100644 index fa994406d610..000000000000 --- a/drivers/staging/ccree/cc_kernel_regs.h +++ /dev/null @@ -1,167 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef __CC_CRYS_KERNEL_H__ -#define __CC_CRYS_KERNEL_H__ - -// -------------------------------------- -// BLOCK: DSCRPTR -// -------------------------------------- -#define CC_DSCRPTR_COMPLETION_COUNTER_REG_OFFSET 0xE00UL -#define CC_DSCRPTR_COMPLETION_COUNTER_COMPLETION_COUNTER_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_COMPLETION_COUNTER_COMPLETION_COUNTER_BIT_SIZE 0x6UL -#define CC_DSCRPTR_COMPLETION_COUNTER_OVERFLOW_COUNTER_BIT_SHIFT 0x6UL -#define CC_DSCRPTR_COMPLETION_COUNTER_OVERFLOW_COUNTER_BIT_SIZE 0x1UL -#define CC_DSCRPTR_SW_RESET_REG_OFFSET 0xE40UL -#define CC_DSCRPTR_SW_RESET_VALUE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_SW_RESET_VALUE_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_SRAM_SIZE_REG_OFFSET 0xE60UL -#define CC_DSCRPTR_QUEUE_SRAM_SIZE_NUM_OF_DSCRPTR_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_SRAM_SIZE_NUM_OF_DSCRPTR_BIT_SIZE 0xAUL -#define CC_DSCRPTR_QUEUE_SRAM_SIZE_DSCRPTR_SRAM_SIZE_BIT_SHIFT 0xAUL -#define CC_DSCRPTR_QUEUE_SRAM_SIZE_DSCRPTR_SRAM_SIZE_BIT_SIZE 0xCUL -#define CC_DSCRPTR_QUEUE_SRAM_SIZE_SRAM_SIZE_BIT_SHIFT 0x16UL -#define CC_DSCRPTR_QUEUE_SRAM_SIZE_SRAM_SIZE_BIT_SIZE 0x3UL -#define CC_DSCRPTR_SINGLE_ADDR_EN_REG_OFFSET 0xE64UL -#define CC_DSCRPTR_SINGLE_ADDR_EN_VALUE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_SINGLE_ADDR_EN_VALUE_BIT_SIZE 0x1UL -#define CC_DSCRPTR_MEASURE_CNTR_REG_OFFSET 0xE68UL -#define CC_DSCRPTR_MEASURE_CNTR_VALUE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_MEASURE_CNTR_VALUE_BIT_SIZE 0x20UL -#define CC_DSCRPTR_QUEUE_WORD0_REG_OFFSET 0xE80UL -#define CC_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SIZE 0x20UL -#define CC_DSCRPTR_QUEUE_WORD1_REG_OFFSET 0xE84UL -#define CC_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SHIFT 0x2UL -#define CC_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SIZE 0x18UL -#define CC_DSCRPTR_QUEUE_WORD1_NS_BIT_BIT_SHIFT 0x1AUL -#define CC_DSCRPTR_QUEUE_WORD1_NS_BIT_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD1_DIN_CONST_VALUE_BIT_SHIFT 0x1BUL -#define CC_DSCRPTR_QUEUE_WORD1_DIN_CONST_VALUE_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD1_NOT_LAST_BIT_SHIFT 0x1CUL -#define CC_DSCRPTR_QUEUE_WORD1_NOT_LAST_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD1_LOCK_QUEUE_BIT_SHIFT 0x1DUL -#define CC_DSCRPTR_QUEUE_WORD1_LOCK_QUEUE_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD1_NOT_USED_BIT_SHIFT 0x1EUL -#define CC_DSCRPTR_QUEUE_WORD1_NOT_USED_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD2_REG_OFFSET 0xE88UL -#define CC_DSCRPTR_QUEUE_WORD2_VALUE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_WORD2_VALUE_BIT_SIZE 0x20UL -#define CC_DSCRPTR_QUEUE_WORD3_REG_OFFSET 0xE8CUL -#define CC_DSCRPTR_QUEUE_WORD3_DOUT_DMA_MODE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_WORD3_DOUT_DMA_MODE_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD3_DOUT_SIZE_BIT_SHIFT 0x2UL -#define CC_DSCRPTR_QUEUE_WORD3_DOUT_SIZE_BIT_SIZE 0x18UL -#define CC_DSCRPTR_QUEUE_WORD3_NS_BIT_BIT_SHIFT 0x1AUL -#define CC_DSCRPTR_QUEUE_WORD3_NS_BIT_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD3_DOUT_LAST_IND_BIT_SHIFT 0x1BUL -#define CC_DSCRPTR_QUEUE_WORD3_DOUT_LAST_IND_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD3_HASH_XOR_BIT_BIT_SHIFT 0x1DUL -#define CC_DSCRPTR_QUEUE_WORD3_HASH_XOR_BIT_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD3_NOT_USED_BIT_SHIFT 0x1EUL -#define CC_DSCRPTR_QUEUE_WORD3_NOT_USED_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD3_QUEUE_LAST_IND_BIT_SHIFT 0x1FUL -#define CC_DSCRPTR_QUEUE_WORD3_QUEUE_LAST_IND_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_REG_OFFSET 0xE90UL -#define CC_DSCRPTR_QUEUE_WORD4_DATA_FLOW_MODE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_WORD4_DATA_FLOW_MODE_BIT_SIZE 0x6UL -#define CC_DSCRPTR_QUEUE_WORD4_AES_SEL_N_HASH_BIT_SHIFT 0x6UL -#define CC_DSCRPTR_QUEUE_WORD4_AES_SEL_N_HASH_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_AES_XOR_CRYPTO_KEY_BIT_SHIFT 0x7UL -#define CC_DSCRPTR_QUEUE_WORD4_AES_XOR_CRYPTO_KEY_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_ACK_NEEDED_BIT_SHIFT 0x8UL -#define CC_DSCRPTR_QUEUE_WORD4_ACK_NEEDED_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_MODE_BIT_SHIFT 0xAUL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_MODE_BIT_SIZE 0x4UL -#define CC_DSCRPTR_QUEUE_WORD4_CMAC_SIZE0_BIT_SHIFT 0xEUL -#define CC_DSCRPTR_QUEUE_WORD4_CMAC_SIZE0_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_DO_BIT_SHIFT 0xFUL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_DO_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF0_BIT_SHIFT 0x11UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF0_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF1_BIT_SHIFT 0x13UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF1_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF2_BIT_SHIFT 0x14UL -#define CC_DSCRPTR_QUEUE_WORD4_CIPHER_CONF2_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD4_KEY_SIZE_BIT_SHIFT 0x16UL -#define CC_DSCRPTR_QUEUE_WORD4_KEY_SIZE_BIT_SIZE 0x2UL -#define CC_DSCRPTR_QUEUE_WORD4_SETUP_OPERATION_BIT_SHIFT 0x18UL -#define CC_DSCRPTR_QUEUE_WORD4_SETUP_OPERATION_BIT_SIZE 0x4UL -#define CC_DSCRPTR_QUEUE_WORD4_DIN_SRAM_ENDIANNESS_BIT_SHIFT 0x1CUL -#define CC_DSCRPTR_QUEUE_WORD4_DIN_SRAM_ENDIANNESS_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_DOUT_SRAM_ENDIANNESS_BIT_SHIFT 0x1DUL -#define CC_DSCRPTR_QUEUE_WORD4_DOUT_SRAM_ENDIANNESS_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_WORD_SWAP_BIT_SHIFT 0x1EUL -#define CC_DSCRPTR_QUEUE_WORD4_WORD_SWAP_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SHIFT 0x1FUL -#define CC_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SIZE 0x1UL -#define CC_DSCRPTR_QUEUE_WORD5_REG_OFFSET 0xE94UL -#define CC_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SIZE 0x10UL -#define CC_DSCRPTR_QUEUE_WORD5_DOUT_ADDR_HIGH_BIT_SHIFT 0x10UL -#define CC_DSCRPTR_QUEUE_WORD5_DOUT_ADDR_HIGH_BIT_SIZE 0x10UL -#define CC_DSCRPTR_QUEUE_WATERMARK_REG_OFFSET 0xE98UL -#define CC_DSCRPTR_QUEUE_WATERMARK_VALUE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_WATERMARK_VALUE_BIT_SIZE 0xAUL -#define CC_DSCRPTR_QUEUE_CONTENT_REG_OFFSET 0xE9CUL -#define CC_DSCRPTR_QUEUE_CONTENT_VALUE_BIT_SHIFT 0x0UL -#define CC_DSCRPTR_QUEUE_CONTENT_VALUE_BIT_SIZE 0xAUL -// -------------------------------------- -// BLOCK: AXI_P -// -------------------------------------- -#define CC_AXIM_MON_INFLIGHT_REG_OFFSET 0xB00UL -#define CC_AXIM_MON_INFLIGHT_VALUE_BIT_SHIFT 0x0UL -#define CC_AXIM_MON_INFLIGHT_VALUE_BIT_SIZE 0x8UL -#define CC_AXIM_MON_INFLIGHTLAST_REG_OFFSET 0xB40UL -#define CC_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SHIFT 0x0UL -#define CC_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SIZE 0x8UL -#define CC_AXIM_MON_COMP_REG_OFFSET 0xB80UL -#define CC_AXIM_MON_COMP_VALUE_BIT_SHIFT 0x0UL -#define CC_AXIM_MON_COMP_VALUE_BIT_SIZE 0x10UL -#define CC_AXIM_MON_ERR_REG_OFFSET 0xBC4UL -#define CC_AXIM_MON_ERR_BRESP_BIT_SHIFT 0x0UL -#define CC_AXIM_MON_ERR_BRESP_BIT_SIZE 0x2UL -#define CC_AXIM_MON_ERR_BID_BIT_SHIFT 0x2UL -#define CC_AXIM_MON_ERR_BID_BIT_SIZE 0x4UL -#define CC_AXIM_MON_ERR_RRESP_BIT_SHIFT 0x10UL -#define CC_AXIM_MON_ERR_RRESP_BIT_SIZE 0x2UL -#define CC_AXIM_MON_ERR_RID_BIT_SHIFT 0x12UL -#define CC_AXIM_MON_ERR_RID_BIT_SIZE 0x4UL -#define CC_AXIM_CFG_REG_OFFSET 0xBE8UL -#define CC_AXIM_CFG_BRESPMASK_BIT_SHIFT 0x4UL -#define CC_AXIM_CFG_BRESPMASK_BIT_SIZE 0x1UL -#define CC_AXIM_CFG_RRESPMASK_BIT_SHIFT 0x5UL -#define CC_AXIM_CFG_RRESPMASK_BIT_SIZE 0x1UL -#define CC_AXIM_CFG_INFLTMASK_BIT_SHIFT 0x6UL -#define CC_AXIM_CFG_INFLTMASK_BIT_SIZE 0x1UL -#define CC_AXIM_CFG_COMPMASK_BIT_SHIFT 0x7UL -#define CC_AXIM_CFG_COMPMASK_BIT_SIZE 0x1UL -#define CC_AXIM_ACE_CONST_REG_OFFSET 0xBECUL -#define CC_AXIM_ACE_CONST_ARDOMAIN_BIT_SHIFT 0x0UL -#define CC_AXIM_ACE_CONST_ARDOMAIN_BIT_SIZE 0x2UL -#define CC_AXIM_ACE_CONST_AWDOMAIN_BIT_SHIFT 0x2UL -#define CC_AXIM_ACE_CONST_AWDOMAIN_BIT_SIZE 0x2UL -#define CC_AXIM_ACE_CONST_ARBAR_BIT_SHIFT 0x4UL -#define CC_AXIM_ACE_CONST_ARBAR_BIT_SIZE 0x2UL -#define CC_AXIM_ACE_CONST_AWBAR_BIT_SHIFT 0x6UL -#define CC_AXIM_ACE_CONST_AWBAR_BIT_SIZE 0x2UL -#define CC_AXIM_ACE_CONST_ARSNOOP_BIT_SHIFT 0x8UL -#define CC_AXIM_ACE_CONST_ARSNOOP_BIT_SIZE 0x4UL -#define CC_AXIM_ACE_CONST_AWSNOOP_NOT_ALIGNED_BIT_SHIFT 0xCUL -#define CC_AXIM_ACE_CONST_AWSNOOP_NOT_ALIGNED_BIT_SIZE 0x3UL -#define CC_AXIM_ACE_CONST_AWSNOOP_ALIGNED_BIT_SHIFT 0xFUL -#define CC_AXIM_ACE_CONST_AWSNOOP_ALIGNED_BIT_SIZE 0x3UL -#define CC_AXIM_ACE_CONST_AWADDR_NOT_MASKED_BIT_SHIFT 0x12UL -#define CC_AXIM_ACE_CONST_AWADDR_NOT_MASKED_BIT_SIZE 0x7UL -#define CC_AXIM_ACE_CONST_AWLEN_VAL_BIT_SHIFT 0x19UL -#define CC_AXIM_ACE_CONST_AWLEN_VAL_BIT_SIZE 0x4UL -#define CC_AXIM_CACHE_PARAMS_REG_OFFSET 0xBF0UL -#define CC_AXIM_CACHE_PARAMS_AWCACHE_LAST_BIT_SHIFT 0x0UL -#define CC_AXIM_CACHE_PARAMS_AWCACHE_LAST_BIT_SIZE 0x4UL -#define CC_AXIM_CACHE_PARAMS_AWCACHE_BIT_SHIFT 0x4UL -#define CC_AXIM_CACHE_PARAMS_AWCACHE_BIT_SIZE 0x4UL -#define CC_AXIM_CACHE_PARAMS_ARCACHE_BIT_SHIFT 0x8UL -#define CC_AXIM_CACHE_PARAMS_ARCACHE_BIT_SIZE 0x4UL -#endif // __CC_CRYS_KERNEL_H__ diff --git a/drivers/staging/ccree/cc_lli_defs.h b/drivers/staging/ccree/cc_lli_defs.h deleted file mode 100644 index 64b15ac9f1d3..000000000000 --- a/drivers/staging/ccree/cc_lli_defs.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef _CC_LLI_DEFS_H_ -#define _CC_LLI_DEFS_H_ - -#include <linux/types.h> - -/* Max DLLI size - * AKA CC_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SIZE - */ -#define DLLI_SIZE_BIT_SIZE 0x18 - -#define CC_MAX_MLLI_ENTRY_SIZE 0xFFFF - -#define LLI_MAX_NUM_OF_DATA_ENTRIES 128 -#define LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES 4 -#define MLLI_TABLE_MIN_ALIGNMENT 4 /* 32 bit alignment */ -#define MAX_NUM_OF_BUFFERS_IN_MLLI 4 -#define MAX_NUM_OF_TOTAL_MLLI_ENTRIES \ - (2 * LLI_MAX_NUM_OF_DATA_ENTRIES + \ - LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES) - -/* Size of entry */ -#define LLI_ENTRY_WORD_SIZE 2 -#define LLI_ENTRY_BYTE_SIZE (LLI_ENTRY_WORD_SIZE * sizeof(u32)) - -/* Word0[31:0] = ADDR[31:0] */ -#define LLI_WORD0_OFFSET 0 -#define LLI_LADDR_BIT_OFFSET 0 -#define LLI_LADDR_BIT_SIZE 32 -/* Word1[31:16] = ADDR[47:32]; Word1[15:0] = SIZE */ -#define LLI_WORD1_OFFSET 1 -#define LLI_SIZE_BIT_OFFSET 0 -#define LLI_SIZE_BIT_SIZE 16 -#define LLI_HADDR_BIT_OFFSET 16 -#define LLI_HADDR_BIT_SIZE 16 - -#define LLI_SIZE_MASK GENMASK((LLI_SIZE_BIT_SIZE - 1), LLI_SIZE_BIT_OFFSET) -#define LLI_HADDR_MASK GENMASK( \ - (LLI_HADDR_BIT_OFFSET + LLI_HADDR_BIT_SIZE - 1),\ - LLI_HADDR_BIT_OFFSET) - -static inline void cc_lli_set_addr(u32 *lli_p, dma_addr_t addr) -{ - lli_p[LLI_WORD0_OFFSET] = (addr & U32_MAX); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - lli_p[LLI_WORD1_OFFSET] &= ~LLI_HADDR_MASK; - lli_p[LLI_WORD1_OFFSET] |= FIELD_PREP(LLI_HADDR_MASK, (addr >> 32)); -#endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT */ -} - -static inline void cc_lli_set_size(u32 *lli_p, u16 size) -{ - lli_p[LLI_WORD1_OFFSET] &= ~LLI_SIZE_MASK; - lli_p[LLI_WORD1_OFFSET] |= FIELD_PREP(LLI_SIZE_MASK, size); -} - -#endif /*_CC_LLI_DEFS_H_*/ diff --git a/drivers/staging/ccree/cc_pm.c b/drivers/staging/ccree/cc_pm.c deleted file mode 100644 index d990f472e89f..000000000000 --- a/drivers/staging/ccree/cc_pm.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/pm_runtime.h> -#include "cc_driver.h" -#include "cc_buffer_mgr.h" -#include "cc_request_mgr.h" -#include "cc_sram_mgr.h" -#include "cc_ivgen.h" -#include "cc_hash.h" -#include "cc_pm.h" - -#define POWER_DOWN_ENABLE 0x01 -#define POWER_DOWN_DISABLE 0x00 - -const struct dev_pm_ops ccree_pm = { - SET_RUNTIME_PM_OPS(cc_pm_suspend, cc_pm_resume, NULL) -}; - -int cc_pm_suspend(struct device *dev) -{ - struct cc_drvdata *drvdata = dev_get_drvdata(dev); - int rc; - - dev_dbg(dev, "set HOST_POWER_DOWN_EN\n"); - cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE); - rc = cc_suspend_req_queue(drvdata); - if (rc) { - dev_err(dev, "cc_suspend_req_queue (%x)\n", rc); - return rc; - } - fini_cc_regs(drvdata); - cc_clk_off(drvdata); - return 0; -} - -int cc_pm_resume(struct device *dev) -{ - int rc; - struct cc_drvdata *drvdata = dev_get_drvdata(dev); - - dev_dbg(dev, "unset HOST_POWER_DOWN_EN\n"); - cc_iowrite(drvdata, CC_REG(HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE); - - rc = cc_clk_on(drvdata); - if (rc) { - dev_err(dev, "failed getting clock back on. We're toast.\n"); - return rc; - } - - rc = init_cc_regs(drvdata, false); - if (rc) { - dev_err(dev, "init_cc_regs (%x)\n", rc); - return rc; - } - - rc = cc_resume_req_queue(drvdata); - if (rc) { - dev_err(dev, "cc_resume_req_queue (%x)\n", rc); - return rc; - } - - /* must be after the queue resuming as it uses the HW queue*/ - cc_init_hash_sram(drvdata); - - cc_init_iv_sram(drvdata); - return 0; -} - -int cc_pm_get(struct device *dev) -{ - int rc = 0; - struct cc_drvdata *drvdata = dev_get_drvdata(dev); - - if (cc_req_queue_suspended(drvdata)) - rc = pm_runtime_get_sync(dev); - else - pm_runtime_get_noresume(dev); - - return rc; -} - -int cc_pm_put_suspend(struct device *dev) -{ - int rc = 0; - struct cc_drvdata *drvdata = dev_get_drvdata(dev); - - if (!cc_req_queue_suspended(drvdata)) { - pm_runtime_mark_last_busy(dev); - rc = pm_runtime_put_autosuspend(dev); - } else { - /* Something wrong happens*/ - dev_err(dev, "request to suspend already suspended queue"); - rc = -EBUSY; - } - return rc; -} - -int cc_pm_init(struct cc_drvdata *drvdata) -{ - int rc = 0; - struct device *dev = drvdata_to_dev(drvdata); - - /* must be before the enabling to avoid resdundent suspending */ - pm_runtime_set_autosuspend_delay(dev, CC_SUSPEND_TIMEOUT); - pm_runtime_use_autosuspend(dev); - /* activate the PM module */ - rc = pm_runtime_set_active(dev); - if (rc) - return rc; - /* enable the PM module*/ - pm_runtime_enable(dev); - - return rc; -} - -void cc_pm_fini(struct cc_drvdata *drvdata) -{ - pm_runtime_disable(drvdata_to_dev(drvdata)); -} diff --git a/drivers/staging/ccree/cc_pm.h b/drivers/staging/ccree/cc_pm.h deleted file mode 100644 index aac8190fea38..000000000000 --- a/drivers/staging/ccree/cc_pm.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -/* \file cc_pm.h - */ - -#ifndef __CC_POWER_MGR_H__ -#define __CC_POWER_MGR_H__ - -#include "cc_driver.h" - -#define CC_SUSPEND_TIMEOUT 3000 - -#if defined(CONFIG_PM) - -extern const struct dev_pm_ops ccree_pm; - -int cc_pm_init(struct cc_drvdata *drvdata); -void cc_pm_fini(struct cc_drvdata *drvdata); -int cc_pm_suspend(struct device *dev); -int cc_pm_resume(struct device *dev); -int cc_pm_get(struct device *dev); -int cc_pm_put_suspend(struct device *dev); - -#else - -static inline int cc_pm_init(struct cc_drvdata *drvdata) -{ - return 0; -} - -static inline void cc_pm_fini(struct cc_drvdata *drvdata) {} - -static inline int cc_pm_suspend(struct device *dev) -{ - return 0; -} - -static inline int cc_pm_resume(struct device *dev) -{ - return 0; -} - -static inline int cc_pm_get(struct device *dev) -{ - return 0; -} - -static inline int cc_pm_put_suspend(struct device *dev) -{ - return 0; -} - -#endif - -#endif /*__POWER_MGR_H__*/ - diff --git a/drivers/staging/ccree/cc_request_mgr.c b/drivers/staging/ccree/cc_request_mgr.c deleted file mode 100644 index 8a7f83407410..000000000000 --- a/drivers/staging/ccree/cc_request_mgr.c +++ /dev/null @@ -1,713 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include <linux/kernel.h> -#include "cc_driver.h" -#include "cc_buffer_mgr.h" -#include "cc_request_mgr.h" -#include "cc_ivgen.h" -#include "cc_pm.h" - -#define CC_MAX_POLL_ITER 10 -/* The highest descriptor count in used */ -#define CC_MAX_DESC_SEQ_LEN 23 - -struct cc_req_mgr_handle { - /* Request manager resources */ - unsigned int hw_queue_size; /* HW capability */ - unsigned int min_free_hw_slots; - unsigned int max_used_sw_slots; - struct cc_crypto_req req_queue[MAX_REQUEST_QUEUE_SIZE]; - u32 req_queue_head; - u32 req_queue_tail; - u32 axi_completed; - u32 q_free_slots; - /* This lock protects access to HW register - * that must be single request at a time - */ - spinlock_t hw_lock; - struct cc_hw_desc compl_desc; - u8 *dummy_comp_buff; - dma_addr_t dummy_comp_buff_dma; - - /* backlog queue */ - struct list_head backlog; - unsigned int bl_len; - spinlock_t bl_lock; /* protect backlog queue */ - -#ifdef COMP_IN_WQ - struct workqueue_struct *workq; - struct delayed_work compwork; -#else - struct tasklet_struct comptask; -#endif - bool is_runtime_suspended; -}; - -struct cc_bl_item { - struct cc_crypto_req creq; - struct cc_hw_desc desc[CC_MAX_DESC_SEQ_LEN]; - unsigned int len; - struct list_head list; - bool notif; -}; - -static void comp_handler(unsigned long devarg); -#ifdef COMP_IN_WQ -static void comp_work_handler(struct work_struct *work); -#endif - -void cc_req_mgr_fini(struct cc_drvdata *drvdata) -{ - struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle; - struct device *dev = drvdata_to_dev(drvdata); - - if (!req_mgr_h) - return; /* Not allocated */ - - if (req_mgr_h->dummy_comp_buff_dma) { - dma_free_coherent(dev, sizeof(u32), req_mgr_h->dummy_comp_buff, - req_mgr_h->dummy_comp_buff_dma); - } - - dev_dbg(dev, "max_used_hw_slots=%d\n", (req_mgr_h->hw_queue_size - - req_mgr_h->min_free_hw_slots)); - dev_dbg(dev, "max_used_sw_slots=%d\n", req_mgr_h->max_used_sw_slots); - -#ifdef COMP_IN_WQ - flush_workqueue(req_mgr_h->workq); - destroy_workqueue(req_mgr_h->workq); -#else - /* Kill tasklet */ - tasklet_kill(&req_mgr_h->comptask); -#endif - memset(req_mgr_h, 0, sizeof(struct cc_req_mgr_handle)); - kfree(req_mgr_h); - drvdata->request_mgr_handle = NULL; -} - -int cc_req_mgr_init(struct cc_drvdata *drvdata) -{ - struct cc_req_mgr_handle *req_mgr_h; - struct device *dev = drvdata_to_dev(drvdata); - int rc = 0; - - req_mgr_h = kzalloc(sizeof(*req_mgr_h), GFP_KERNEL); - if (!req_mgr_h) { - rc = -ENOMEM; - goto req_mgr_init_err; - } - - drvdata->request_mgr_handle = req_mgr_h; - - spin_lock_init(&req_mgr_h->hw_lock); - spin_lock_init(&req_mgr_h->bl_lock); - INIT_LIST_HEAD(&req_mgr_h->backlog); - -#ifdef COMP_IN_WQ - dev_dbg(dev, "Initializing completion workqueue\n"); - req_mgr_h->workq = create_singlethread_workqueue("arm_cc7x_wq"); - if (!req_mgr_h->workq) { - dev_err(dev, "Failed creating work queue\n"); - rc = -ENOMEM; - goto req_mgr_init_err; - } - INIT_DELAYED_WORK(&req_mgr_h->compwork, comp_work_handler); -#else - dev_dbg(dev, "Initializing completion tasklet\n"); - tasklet_init(&req_mgr_h->comptask, comp_handler, - (unsigned long)drvdata); -#endif - req_mgr_h->hw_queue_size = cc_ioread(drvdata, - CC_REG(DSCRPTR_QUEUE_SRAM_SIZE)); - dev_dbg(dev, "hw_queue_size=0x%08X\n", req_mgr_h->hw_queue_size); - if (req_mgr_h->hw_queue_size < MIN_HW_QUEUE_SIZE) { - dev_err(dev, "Invalid HW queue size = %u (Min. required is %u)\n", - req_mgr_h->hw_queue_size, MIN_HW_QUEUE_SIZE); - rc = -ENOMEM; - goto req_mgr_init_err; - } - req_mgr_h->min_free_hw_slots = req_mgr_h->hw_queue_size; - req_mgr_h->max_used_sw_slots = 0; - - /* Allocate DMA word for "dummy" completion descriptor use */ - req_mgr_h->dummy_comp_buff = - dma_alloc_coherent(dev, sizeof(u32), - &req_mgr_h->dummy_comp_buff_dma, - GFP_KERNEL); - if (!req_mgr_h->dummy_comp_buff) { - dev_err(dev, "Not enough memory to allocate DMA (%zu) dropped buffer\n", - sizeof(u32)); - rc = -ENOMEM; - goto req_mgr_init_err; - } - - /* Init. "dummy" completion descriptor */ - hw_desc_init(&req_mgr_h->compl_desc); - set_din_const(&req_mgr_h->compl_desc, 0, sizeof(u32)); - set_dout_dlli(&req_mgr_h->compl_desc, req_mgr_h->dummy_comp_buff_dma, - sizeof(u32), NS_BIT, 1); - set_flow_mode(&req_mgr_h->compl_desc, BYPASS); - set_queue_last_ind(&req_mgr_h->compl_desc); - - return 0; - -req_mgr_init_err: - cc_req_mgr_fini(drvdata); - return rc; -} - -static void enqueue_seq(struct cc_drvdata *drvdata, struct cc_hw_desc seq[], - unsigned int seq_len) -{ - int i, w; - void __iomem *reg = drvdata->cc_base + CC_REG(DSCRPTR_QUEUE_WORD0); - struct device *dev = drvdata_to_dev(drvdata); - - /* - * We do indeed write all 6 command words to the same - * register. The HW supports this. - */ - - for (i = 0; i < seq_len; i++) { - for (w = 0; w <= 5; w++) - writel_relaxed(seq[i].word[w], reg); - - if (cc_dump_desc) - dev_dbg(dev, "desc[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", - i, seq[i].word[0], seq[i].word[1], - seq[i].word[2], seq[i].word[3], - seq[i].word[4], seq[i].word[5]); - } -} - -/*! - * Completion will take place if and only if user requested completion - * by cc_send_sync_request(). - * - * \param dev - * \param dx_compl_h The completion event to signal - */ -static void request_mgr_complete(struct device *dev, void *dx_compl_h, - int dummy) -{ - struct completion *this_compl = dx_compl_h; - - complete(this_compl); -} - -static int cc_queues_status(struct cc_drvdata *drvdata, - struct cc_req_mgr_handle *req_mgr_h, - unsigned int total_seq_len) -{ - unsigned long poll_queue; - struct device *dev = drvdata_to_dev(drvdata); - - /* SW queue is checked only once as it will not - * be chaned during the poll because the spinlock_bh - * is held by the thread - */ - if (((req_mgr_h->req_queue_head + 1) & (MAX_REQUEST_QUEUE_SIZE - 1)) == - req_mgr_h->req_queue_tail) { - dev_err(dev, "SW FIFO is full. req_queue_head=%d sw_fifo_len=%d\n", - req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE); - return -ENOSPC; - } - - if (req_mgr_h->q_free_slots >= total_seq_len) - return 0; - - /* Wait for space in HW queue. Poll constant num of iterations. */ - for (poll_queue = 0; poll_queue < CC_MAX_POLL_ITER ; poll_queue++) { - req_mgr_h->q_free_slots = - cc_ioread(drvdata, CC_REG(DSCRPTR_QUEUE_CONTENT)); - if (req_mgr_h->q_free_slots < req_mgr_h->min_free_hw_slots) - req_mgr_h->min_free_hw_slots = req_mgr_h->q_free_slots; - - if (req_mgr_h->q_free_slots >= total_seq_len) { - /* If there is enough place return */ - return 0; - } - - dev_dbg(dev, "HW FIFO is full. q_free_slots=%d total_seq_len=%d\n", - req_mgr_h->q_free_slots, total_seq_len); - } - /* No room in the HW queue try again later */ - dev_dbg(dev, "HW FIFO full, timeout. req_queue_head=%d sw_fifo_len=%d q_free_slots=%d total_seq_len=%d\n", - req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE, - req_mgr_h->q_free_slots, total_seq_len); - return -ENOSPC; -} - -/*! - * Enqueue caller request to crypto hardware. - * Need to be called with HW lock held and PM running - * - * \param drvdata - * \param cc_req The request to enqueue - * \param desc The crypto sequence - * \param len The crypto sequence length - * \param add_comp If "true": add an artificial dout DMA to mark completion - * - * \return int Returns -EINPROGRESS or error code - */ -static int cc_do_send_request(struct cc_drvdata *drvdata, - struct cc_crypto_req *cc_req, - struct cc_hw_desc *desc, unsigned int len, - bool add_comp, bool ivgen) -{ - struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle; - unsigned int used_sw_slots; - unsigned int iv_seq_len = 0; - unsigned int total_seq_len = len; /*initial sequence length*/ - struct cc_hw_desc iv_seq[CC_IVPOOL_SEQ_LEN]; - struct device *dev = drvdata_to_dev(drvdata); - int rc; - - if (ivgen) { - dev_dbg(dev, "Acquire IV from pool into %d DMA addresses %pad, %pad, %pad, IV-size=%u\n", - cc_req->ivgen_dma_addr_len, - &cc_req->ivgen_dma_addr[0], - &cc_req->ivgen_dma_addr[1], - &cc_req->ivgen_dma_addr[2], - cc_req->ivgen_size); - - /* Acquire IV from pool */ - rc = cc_get_iv(drvdata, cc_req->ivgen_dma_addr, - cc_req->ivgen_dma_addr_len, - cc_req->ivgen_size, iv_seq, &iv_seq_len); - - if (rc) { - dev_err(dev, "Failed to generate IV (rc=%d)\n", rc); - return rc; - } - - total_seq_len += iv_seq_len; - } - - used_sw_slots = ((req_mgr_h->req_queue_head - - req_mgr_h->req_queue_tail) & - (MAX_REQUEST_QUEUE_SIZE - 1)); - if (used_sw_slots > req_mgr_h->max_used_sw_slots) - req_mgr_h->max_used_sw_slots = used_sw_slots; - - /* Enqueue request - must be locked with HW lock*/ - req_mgr_h->req_queue[req_mgr_h->req_queue_head] = *cc_req; - req_mgr_h->req_queue_head = (req_mgr_h->req_queue_head + 1) & - (MAX_REQUEST_QUEUE_SIZE - 1); - /* TODO: Use circ_buf.h ? */ - - dev_dbg(dev, "Enqueue request head=%u\n", req_mgr_h->req_queue_head); - - /* - * We are about to push command to the HW via the command registers - * that may refernece hsot memory. We need to issue a memory barrier - * to make sure there are no outstnading memory writes - */ - wmb(); - - /* STAT_PHASE_4: Push sequence */ - if (ivgen) - enqueue_seq(drvdata, iv_seq, iv_seq_len); - - enqueue_seq(drvdata, desc, len); - - if (add_comp) { - enqueue_seq(drvdata, &req_mgr_h->compl_desc, 1); - total_seq_len++; - } - - if (req_mgr_h->q_free_slots < total_seq_len) { - /* This situation should never occur. Maybe indicating problem - * with resuming power. Set the free slot count to 0 and hope - * for the best. - */ - dev_err(dev, "HW free slot count mismatch."); - req_mgr_h->q_free_slots = 0; - } else { - /* Update the free slots in HW queue */ - req_mgr_h->q_free_slots -= total_seq_len; - } - - /* Operation still in process */ - return -EINPROGRESS; -} - -static void cc_enqueue_backlog(struct cc_drvdata *drvdata, - struct cc_bl_item *bli) -{ - struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle; - - spin_lock_bh(&mgr->bl_lock); - list_add_tail(&bli->list, &mgr->backlog); - ++mgr->bl_len; - spin_unlock_bh(&mgr->bl_lock); - tasklet_schedule(&mgr->comptask); -} - -static void cc_proc_backlog(struct cc_drvdata *drvdata) -{ - struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle; - struct cc_bl_item *bli; - struct cc_crypto_req *creq; - struct crypto_async_request *req; - bool ivgen; - unsigned int total_len; - struct device *dev = drvdata_to_dev(drvdata); - int rc; - - spin_lock(&mgr->bl_lock); - - while (mgr->bl_len) { - bli = list_first_entry(&mgr->backlog, struct cc_bl_item, list); - spin_unlock(&mgr->bl_lock); - - creq = &bli->creq; - req = (struct crypto_async_request *)creq->user_arg; - - /* - * Notify the request we're moving out of the backlog - * but only if we haven't done so already. - */ - if (!bli->notif) { - req->complete(req, -EINPROGRESS); - bli->notif = true; - } - - ivgen = !!creq->ivgen_dma_addr_len; - total_len = bli->len + (ivgen ? CC_IVPOOL_SEQ_LEN : 0); - - spin_lock(&mgr->hw_lock); - - rc = cc_queues_status(drvdata, mgr, total_len); - if (rc) { - /* - * There is still not room in the FIFO for - * this request. Bail out. We'll return here - * on the next completion irq. - */ - spin_unlock(&mgr->hw_lock); - return; - } - - rc = cc_do_send_request(drvdata, &bli->creq, bli->desc, - bli->len, false, ivgen); - - spin_unlock(&mgr->hw_lock); - - if (rc != -EINPROGRESS) { - cc_pm_put_suspend(dev); - creq->user_cb(dev, req, rc); - } - - /* Remove ourselves from the backlog list */ - spin_lock(&mgr->bl_lock); - list_del(&bli->list); - --mgr->bl_len; - } - - spin_unlock(&mgr->bl_lock); -} - -int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req, - struct cc_hw_desc *desc, unsigned int len, - struct crypto_async_request *req) -{ - int rc; - struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle; - bool ivgen = !!cc_req->ivgen_dma_addr_len; - unsigned int total_len = len + (ivgen ? CC_IVPOOL_SEQ_LEN : 0); - struct device *dev = drvdata_to_dev(drvdata); - bool backlog_ok = req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG; - gfp_t flags = cc_gfp_flags(req); - struct cc_bl_item *bli; - - rc = cc_pm_get(dev); - if (rc) { - dev_err(dev, "ssi_power_mgr_runtime_get returned %x\n", rc); - return rc; - } - - spin_lock_bh(&mgr->hw_lock); - rc = cc_queues_status(drvdata, mgr, total_len); - -#ifdef CC_DEBUG_FORCE_BACKLOG - if (backlog_ok) - rc = -ENOSPC; -#endif /* CC_DEBUG_FORCE_BACKLOG */ - - if (rc == -ENOSPC && backlog_ok) { - spin_unlock_bh(&mgr->hw_lock); - - bli = kmalloc(sizeof(*bli), flags); - if (!bli) { - cc_pm_put_suspend(dev); - return -ENOMEM; - } - - memcpy(&bli->creq, cc_req, sizeof(*cc_req)); - memcpy(&bli->desc, desc, len * sizeof(*desc)); - bli->len = len; - bli->notif = false; - cc_enqueue_backlog(drvdata, bli); - return -EBUSY; - } - - if (!rc) - rc = cc_do_send_request(drvdata, cc_req, desc, len, false, - ivgen); - - spin_unlock_bh(&mgr->hw_lock); - return rc; -} - -int cc_send_sync_request(struct cc_drvdata *drvdata, - struct cc_crypto_req *cc_req, struct cc_hw_desc *desc, - unsigned int len) -{ - int rc; - struct device *dev = drvdata_to_dev(drvdata); - struct cc_req_mgr_handle *mgr = drvdata->request_mgr_handle; - - init_completion(&cc_req->seq_compl); - cc_req->user_cb = request_mgr_complete; - cc_req->user_arg = &cc_req->seq_compl; - - rc = cc_pm_get(dev); - if (rc) { - dev_err(dev, "ssi_power_mgr_runtime_get returned %x\n", rc); - return rc; - } - - while (true) { - spin_lock_bh(&mgr->hw_lock); - rc = cc_queues_status(drvdata, mgr, len + 1); - - if (!rc) - break; - - spin_unlock_bh(&mgr->hw_lock); - if (rc != -EAGAIN) { - cc_pm_put_suspend(dev); - return rc; - } - wait_for_completion_interruptible(&drvdata->hw_queue_avail); - reinit_completion(&drvdata->hw_queue_avail); - } - - rc = cc_do_send_request(drvdata, cc_req, desc, len, true, false); - spin_unlock_bh(&mgr->hw_lock); - - if (rc != -EINPROGRESS) { - cc_pm_put_suspend(dev); - return rc; - } - - wait_for_completion(&cc_req->seq_compl); - return 0; -} - -/*! - * Enqueue caller request to crypto hardware during init process. - * assume this function is not called in middle of a flow, - * since we set QUEUE_LAST_IND flag in the last descriptor. - * - * \param drvdata - * \param desc The crypto sequence - * \param len The crypto sequence length - * - * \return int Returns "0" upon success - */ -int send_request_init(struct cc_drvdata *drvdata, struct cc_hw_desc *desc, - unsigned int len) -{ - struct cc_req_mgr_handle *req_mgr_h = drvdata->request_mgr_handle; - unsigned int total_seq_len = len; /*initial sequence length*/ - int rc = 0; - - /* Wait for space in HW and SW FIFO. Poll for as much as FIFO_TIMEOUT. - */ - rc = cc_queues_status(drvdata, req_mgr_h, total_seq_len); - if (rc) - return rc; - - set_queue_last_ind(&desc[(len - 1)]); - - /* - * We are about to push command to the HW via the command registers - * that may refernece hsot memory. We need to issue a memory barrier - * to make sure there are no outstnading memory writes - */ - wmb(); - enqueue_seq(drvdata, desc, len); - - /* Update the free slots in HW queue */ - req_mgr_h->q_free_slots = - cc_ioread(drvdata, CC_REG(DSCRPTR_QUEUE_CONTENT)); - - return 0; -} - -void complete_request(struct cc_drvdata *drvdata) -{ - struct cc_req_mgr_handle *request_mgr_handle = - drvdata->request_mgr_handle; - - complete(&drvdata->hw_queue_avail); -#ifdef COMP_IN_WQ - queue_delayed_work(request_mgr_handle->workq, - &request_mgr_handle->compwork, 0); -#else - tasklet_schedule(&request_mgr_handle->comptask); -#endif -} - -#ifdef COMP_IN_WQ -static void comp_work_handler(struct work_struct *work) -{ - struct cc_drvdata *drvdata = - container_of(work, struct cc_drvdata, compwork.work); - - comp_handler((unsigned long)drvdata); -} -#endif - -static void proc_completions(struct cc_drvdata *drvdata) -{ - struct cc_crypto_req *cc_req; - struct device *dev = drvdata_to_dev(drvdata); - struct cc_req_mgr_handle *request_mgr_handle = - drvdata->request_mgr_handle; - unsigned int *tail = &request_mgr_handle->req_queue_tail; - unsigned int *head = &request_mgr_handle->req_queue_head; - - while (request_mgr_handle->axi_completed) { - request_mgr_handle->axi_completed--; - - /* Dequeue request */ - if (*head == *tail) { - /* We are supposed to handle a completion but our - * queue is empty. This is not normal. Return and - * hope for the best. - */ - dev_err(dev, "Request queue is empty head == tail %u\n", - *head); - break; - } - - cc_req = &request_mgr_handle->req_queue[*tail]; - - if (cc_req->user_cb) - cc_req->user_cb(dev, cc_req->user_arg, 0); - *tail = (*tail + 1) & (MAX_REQUEST_QUEUE_SIZE - 1); - dev_dbg(dev, "Dequeue request tail=%u\n", *tail); - dev_dbg(dev, "Request completed. axi_completed=%d\n", - request_mgr_handle->axi_completed); - cc_pm_put_suspend(dev); - } -} - -static inline u32 cc_axi_comp_count(struct cc_drvdata *drvdata) -{ - return FIELD_GET(AXIM_MON_COMP_VALUE, - cc_ioread(drvdata, CC_REG(AXIM_MON_COMP))); -} - -/* Deferred service handler, run as interrupt-fired tasklet */ -static void comp_handler(unsigned long devarg) -{ - struct cc_drvdata *drvdata = (struct cc_drvdata *)devarg; - struct cc_req_mgr_handle *request_mgr_handle = - drvdata->request_mgr_handle; - - u32 irq; - - irq = (drvdata->irq & CC_COMP_IRQ_MASK); - - if (irq & CC_COMP_IRQ_MASK) { - /* To avoid the interrupt from firing as we unmask it, - * we clear it now - */ - cc_iowrite(drvdata, CC_REG(HOST_ICR), CC_COMP_IRQ_MASK); - - /* Avoid race with above clear: Test completion counter - * once more - */ - request_mgr_handle->axi_completed += - cc_axi_comp_count(drvdata); - - while (request_mgr_handle->axi_completed) { - do { - proc_completions(drvdata); - /* At this point (after proc_completions()), - * request_mgr_handle->axi_completed is 0. - */ - request_mgr_handle->axi_completed = - cc_axi_comp_count(drvdata); - } while (request_mgr_handle->axi_completed > 0); - - cc_iowrite(drvdata, CC_REG(HOST_ICR), - CC_COMP_IRQ_MASK); - - request_mgr_handle->axi_completed += - cc_axi_comp_count(drvdata); - } - } - /* after verifing that there is nothing to do, - * unmask AXI completion interrupt - */ - cc_iowrite(drvdata, CC_REG(HOST_IMR), - cc_ioread(drvdata, CC_REG(HOST_IMR)) & ~irq); - - cc_proc_backlog(drvdata); -} - -/* - * resume the queue configuration - no need to take the lock as this happens - * inside the spin lock protection - */ -#if defined(CONFIG_PM) -int cc_resume_req_queue(struct cc_drvdata *drvdata) -{ - struct cc_req_mgr_handle *request_mgr_handle = - drvdata->request_mgr_handle; - - spin_lock_bh(&request_mgr_handle->hw_lock); - request_mgr_handle->is_runtime_suspended = false; - spin_unlock_bh(&request_mgr_handle->hw_lock); - - return 0; -} - -/* - * suspend the queue configuration. Since it is used for the runtime suspend - * only verify that the queue can be suspended. - */ -int cc_suspend_req_queue(struct cc_drvdata *drvdata) -{ - struct cc_req_mgr_handle *request_mgr_handle = - drvdata->request_mgr_handle; - - /* lock the send_request */ - spin_lock_bh(&request_mgr_handle->hw_lock); - if (request_mgr_handle->req_queue_head != - request_mgr_handle->req_queue_tail) { - spin_unlock_bh(&request_mgr_handle->hw_lock); - return -EBUSY; - } - request_mgr_handle->is_runtime_suspended = true; - spin_unlock_bh(&request_mgr_handle->hw_lock); - - return 0; -} - -bool cc_req_queue_suspended(struct cc_drvdata *drvdata) -{ - struct cc_req_mgr_handle *request_mgr_handle = - drvdata->request_mgr_handle; - - return request_mgr_handle->is_runtime_suspended; -} - -#endif - diff --git a/drivers/staging/ccree/cc_request_mgr.h b/drivers/staging/ccree/cc_request_mgr.h deleted file mode 100644 index 573cb97af085..000000000000 --- a/drivers/staging/ccree/cc_request_mgr.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -/* \file cc_request_mgr.h - * Request Manager - */ - -#ifndef __REQUEST_MGR_H__ -#define __REQUEST_MGR_H__ - -#include "cc_hw_queue_defs.h" - -int cc_req_mgr_init(struct cc_drvdata *drvdata); - -/*! - * Enqueue caller request to crypto hardware. - * - * \param drvdata - * \param cc_req The request to enqueue - * \param desc The crypto sequence - * \param len The crypto sequence length - * \param is_dout If "true": completion is handled by the caller - * If "false": this function adds a dummy descriptor completion - * and waits upon completion signal. - * - * \return int Returns -EINPROGRESS or error - */ -int cc_send_request(struct cc_drvdata *drvdata, struct cc_crypto_req *cc_req, - struct cc_hw_desc *desc, unsigned int len, - struct crypto_async_request *req); - -int cc_send_sync_request(struct cc_drvdata *drvdata, - struct cc_crypto_req *cc_req, struct cc_hw_desc *desc, - unsigned int len); - -int send_request_init(struct cc_drvdata *drvdata, struct cc_hw_desc *desc, - unsigned int len); - -void complete_request(struct cc_drvdata *drvdata); - -void cc_req_mgr_fini(struct cc_drvdata *drvdata); - -#if defined(CONFIG_PM) -int cc_resume_req_queue(struct cc_drvdata *drvdata); - -int cc_suspend_req_queue(struct cc_drvdata *drvdata); - -bool cc_req_queue_suspended(struct cc_drvdata *drvdata); -#endif - -#endif /*__REQUEST_MGR_H__*/ diff --git a/drivers/staging/ccree/cc_sram_mgr.c b/drivers/staging/ccree/cc_sram_mgr.c deleted file mode 100644 index d1f8a9cc1c0f..000000000000 --- a/drivers/staging/ccree/cc_sram_mgr.c +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#include "cc_driver.h" -#include "cc_sram_mgr.h" - -/** - * struct cc_sram_ctx -Internal RAM context manager - * @sram_free_offset: the offset to the non-allocated area - */ -struct cc_sram_ctx { - cc_sram_addr_t sram_free_offset; -}; - -/** - * cc_sram_mgr_fini() - Cleanup SRAM pool. - * - * @drvdata: Associated device driver context - */ -void cc_sram_mgr_fini(struct cc_drvdata *drvdata) -{ - /* Free "this" context */ - kfree(drvdata->sram_mgr_handle); -} - -/** - * cc_sram_mgr_init() - Initializes SRAM pool. - * The pool starts right at the beginning of SRAM. - * Returns zero for success, negative value otherwise. - * - * @drvdata: Associated device driver context - */ -int cc_sram_mgr_init(struct cc_drvdata *drvdata) -{ - struct cc_sram_ctx *ctx; - - /* Allocate "this" context */ - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - - if (!ctx) - return -ENOMEM; - - drvdata->sram_mgr_handle = ctx; - - return 0; -} - -/*! - * Allocated buffer from SRAM pool. - * Note: Caller is responsible to free the LAST allocated buffer. - * This function does not taking care of any fragmentation may occur - * by the order of calls to alloc/free. - * - * \param drvdata - * \param size The requested bytes to allocate - */ -cc_sram_addr_t cc_sram_alloc(struct cc_drvdata *drvdata, u32 size) -{ - struct cc_sram_ctx *smgr_ctx = drvdata->sram_mgr_handle; - struct device *dev = drvdata_to_dev(drvdata); - cc_sram_addr_t p; - - if ((size & 0x3)) { - dev_err(dev, "Requested buffer size (%u) is not multiple of 4", - size); - return NULL_SRAM_ADDR; - } - if (size > (CC_CC_SRAM_SIZE - smgr_ctx->sram_free_offset)) { - dev_err(dev, "Not enough space to allocate %u B (at offset %llu)\n", - size, smgr_ctx->sram_free_offset); - return NULL_SRAM_ADDR; - } - - p = smgr_ctx->sram_free_offset; - smgr_ctx->sram_free_offset += size; - dev_dbg(dev, "Allocated %u B @ %u\n", size, (unsigned int)p); - return p; -} - -/** - * cc_set_sram_desc() - Create const descriptors sequence to - * set values in given array into SRAM. - * Note: each const value can't exceed word size. - * - * @src: A pointer to array of words to set as consts. - * @dst: The target SRAM buffer to set into - * @nelements: The number of words in "src" array - * @seq: A pointer to the given IN/OUT descriptor sequence - * @seq_len: A pointer to the given IN/OUT sequence length - */ -void cc_set_sram_desc(const u32 *src, cc_sram_addr_t dst, - unsigned int nelement, struct cc_hw_desc *seq, - unsigned int *seq_len) -{ - u32 i; - unsigned int idx = *seq_len; - - for (i = 0; i < nelement; i++, idx++) { - hw_desc_init(&seq[idx]); - set_din_const(&seq[idx], src[i], sizeof(u32)); - set_dout_sram(&seq[idx], dst + (i * sizeof(u32)), sizeof(u32)); - set_flow_mode(&seq[idx], BYPASS); - } - - *seq_len = idx; -} - diff --git a/drivers/staging/ccree/cc_sram_mgr.h b/drivers/staging/ccree/cc_sram_mgr.h deleted file mode 100644 index d48649fb3323..000000000000 --- a/drivers/staging/ccree/cc_sram_mgr.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2012-2018 ARM Limited or its affiliates. */ - -#ifndef __CC_SRAM_MGR_H__ -#define __CC_SRAM_MGR_H__ - -#ifndef CC_CC_SRAM_SIZE -#define CC_CC_SRAM_SIZE 4096 -#endif - -struct cc_drvdata; - -/** - * Address (offset) within CC internal SRAM - */ - -typedef u64 cc_sram_addr_t; - -#define NULL_SRAM_ADDR ((cc_sram_addr_t)-1) - -/*! - * Initializes SRAM pool. - * The first X bytes of SRAM are reserved for ROM usage, hence, pool - * starts right after X bytes. - * - * \param drvdata - * - * \return int Zero for success, negative value otherwise. - */ -int cc_sram_mgr_init(struct cc_drvdata *drvdata); - -/*! - * Uninits SRAM pool. - * - * \param drvdata - */ -void cc_sram_mgr_fini(struct cc_drvdata *drvdata); - -/*! - * Allocated buffer from SRAM pool. - * Note: Caller is responsible to free the LAST allocated buffer. - * This function does not taking care of any fragmentation may occur - * by the order of calls to alloc/free. - * - * \param drvdata - * \param size The requested bytes to allocate - */ -cc_sram_addr_t cc_sram_alloc(struct cc_drvdata *drvdata, u32 size); - -/** - * cc_set_sram_desc() - Create const descriptors sequence to - * set values in given array into SRAM. - * Note: each const value can't exceed word size. - * - * @src: A pointer to array of words to set as consts. - * @dst: The target SRAM buffer to set into - * @nelements: The number of words in "src" array - * @seq: A pointer to the given IN/OUT descriptor sequence - * @seq_len: A pointer to the given IN/OUT sequence length - */ -void cc_set_sram_desc(const u32 *src, cc_sram_addr_t dst, - unsigned int nelement, struct cc_hw_desc *seq, - unsigned int *seq_len); - -#endif /*__CC_SRAM_MGR_H__*/ diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index d39b4eabce8d..e21840e9002d 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -58,12 +58,11 @@ static int pci6208_ao_insn_write(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int val = s->readback[chan]; int ret; int i; for (i = 0; i < insn->n; i++) { - val = data[i]; + unsigned int val = data[i]; /* D/A transfer rate is 2.2us */ ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0); diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index b657beedd5ff..fdd81c3beb51 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1488,11 +1488,10 @@ static int alloc_and_init_dma_members(struct comedi_device *dev) for (i = 0; i < AO_DMA_RING_COUNT; i++) { if (ao_cmd_is_supported(board)) { devpriv->ao_buffer[i] = - dma_alloc_coherent(&pcidev->dev, - DMA_BUFFER_SIZE, - &devpriv-> - ao_buffer_bus_addr[i], - GFP_KERNEL); + dma_alloc_coherent(&pcidev->dev, + DMA_BUFFER_SIZE, + &devpriv->ao_buffer_bus_addr[i], + GFP_KERNEL); if (!devpriv->ao_buffer[i]) return -ENOMEM; } @@ -1701,7 +1700,7 @@ static void i2c_write(struct comedi_device *dev, unsigned int address, * eeprom and i2c bus */ - /* make sure we dont send anything to eeprom */ + /* make sure we don't send anything to eeprom */ devpriv->plx_control_bits &= ~PLX_CNTRL_EECS; i2c_stop(dev); @@ -2463,20 +2462,21 @@ static int setup_channel_queue(struct comedi_device *dev, writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); /* load external queue */ for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + int use_differential; + bits = 0; /* set channel */ - bits |= adc_chan_bits(CR_CHAN(cmd-> - chanlist[i])); + bits |= adc_chan_bits(CR_CHAN(chanspec)); /* set gain */ bits |= ai_range_bits_6xxx(dev, - CR_RANGE(cmd-> - chanlist - [i])); + CR_RANGE(chanspec)); /* set single-ended / differential */ - bits |= se_diff_bit_6xxx(dev, - CR_AREF(cmd-> - chanlist[i]) == - AREF_DIFF); + use_differential = 0; + if (CR_AREF(chanspec) == AREF_DIFF) + use_differential = 1; + bits |= se_diff_bit_6xxx(dev, use_differential); + if (CR_AREF(cmd->chanlist[i]) == AREF_COMMON) bits |= ADC_COMMON_BIT; /* mark end of queue */ @@ -3248,17 +3248,15 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) return 0; } -static inline int external_ai_queue_in_use(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static inline int external_ai_queue_in_use(struct comedi_device *dev) { const struct pcidas64_board *board = dev->board_ptr; - if (s->busy) + if (!dev->read_subdev->busy) return 0; if (board->layout == LAYOUT_4020) return 0; - else if (use_internal_queue_6xxx(cmd)) + else if (use_internal_queue_6xxx(&dev->read_subdev->async->cmd)) return 0; return 1; } @@ -3292,7 +3290,7 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct pcidas64_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - if (external_ai_queue_in_use(dev, s, cmd)) { + if (external_ai_queue_in_use(dev)) { warn_external_queue(dev); return -EBUSY; } diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 74ff204b585d..81eb51b1be25 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -619,7 +619,7 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 2b : and mutually compatible */ - /* make sure scan_begin_src and convert_src dont conflict */ + /* make sure scan_begin_src and convert_src don't conflict */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) err |= -EINVAL; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 72f8ed2c5008..4e36377b592a 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -407,7 +407,7 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) if (num_samples > cmd->stop_arg * cmd->chanlist_len) num_samples = cmd->stop_arg * cmd->chanlist_len; } - /* make sure we dont try to get too many points if fifo has overrun */ + /* make sure we don't try to get too many points if fifo has overrun */ if (num_samples > DAS16M1_AI_FIFO_SZ) num_samples = DAS16M1_AI_FIFO_SZ; insw(dev->iobase, devpriv->ai_buffer, num_samples); diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 201f4f96c182..c3c88e6d298f 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -295,7 +295,6 @@ static int jr3_pci_open(struct comedi_device *dev) struct comedi_subdevice *s; int i; - dev_dbg(dev->class_dev, "jr3_pci_open\n"); for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; spriv = s->private; diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index b9e9ab548c4b..2b7bfe0dd7f3 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -224,10 +224,11 @@ static int ni_isapnp_find_board(struct pnp_dev **dev) int i; for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { - isapnp_dev = pnp_find_dev(NULL, - ISAPNP_VENDOR('N', 'I', 'C'), - ISAPNP_FUNCTION(ni_boards[i]. - isapnp_id), NULL); + isapnp_dev = + pnp_find_dev(NULL, + ISAPNP_VENDOR('N', 'I', 'C'), + ISAPNP_FUNCTION(ni_boards[i].isapnp_id), + NULL); if (!isapnp_dev || !isapnp_dev->card) continue; diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 5d610af6799f..e40a2c0a9543 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1275,6 +1275,8 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) ack |= NISTC_INTA_ACK_AI_START; if (a_status & NISTC_AI_STATUS1_STOP) ack |= NISTC_INTA_ACK_AI_STOP; + if (a_status & NISTC_AI_STATUS1_OVER) + ack |= NISTC_INTA_ACK_AI_ERR; if (ack) ni_stc_writew(dev, ack, NISTC_INTA_ACK_REG); } @@ -1965,7 +1967,8 @@ static void ni_cmd_set_mite_transfer(struct mite_ring *ring, if (nbytes > sdev->async->prealloc_bufsz) { if (cmd->stop_arg > 0) dev_err(sdev->device->class_dev, - "ni_cmd_set_mite_transfer: tried exact data transfer limits greater than buffer size\n"); + "%s: tried exact data transfer limits greater than buffer size\n", + __func__); /* * we can only transfer up to the size of the buffer. In this @@ -1978,7 +1981,8 @@ static void ni_cmd_set_mite_transfer(struct mite_ring *ring, mite_init_ring_descriptors(ring, sdev, nbytes); #else dev_err(sdev->device->class_dev, - "ni_cmd_set_mite_transfer: exact data transfer limits not implemented yet without DMA\n"); + "%s: exact data transfer limits not implemented yet without DMA\n", + __func__); #endif } @@ -4687,7 +4691,7 @@ static int cs5529_do_conversion(struct comedi_device *dev, retval = cs5529_wait_for_idle(dev); if (retval) { dev_err(dev->class_dev, - "timeout or signal in cs5529_do_conversion()\n"); + "timeout or signal in %s()\n", __func__); return -ETIME; } status = ni_ao_win_inw(dev, NI67XX_CAL_STATUS_REG); diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index cb9d4c3a1926..831088c5cabb 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -9,7 +9,7 @@ /* * References: * DAQ-STC Technical Reference Manual -*/ + */ #ifndef _COMEDI_NI_STC_H #define _COMEDI_NI_STC_H diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 802f51e46405..ea194aa01a64 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -248,7 +248,7 @@ static irqreturn_t daqp_interrupt(int irq, void *dev_id) if (loop_limit <= 0) { dev_warn(dev->class_dev, - "loop_limit reached in daqp_interrupt()\n"); + "loop_limit reached in %s()\n", __func__); s->async->events |= COMEDI_CB_ERROR; } diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 0b3cfe934e14..f5af6f4069dc 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -1700,7 +1700,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (devpriv->ai_cmd_running) { dev_err(dev->class_dev, - "s626_ai_cmd: Another ai_cmd is running\n"); + "%s: Another ai_cmd is running\n", __func__); return -EBUSY; } /* disable interrupt */ @@ -2268,10 +2268,10 @@ static int s626_initialize(struct comedi_device *dev) */ { struct comedi_subdevice *s = dev->read_subdev; - uint8_t poll_list; - uint16_t adc_data; - uint16_t start_val; - uint16_t index; + u8 poll_list; + u16 adc_data; + u16 start_val; + u16 index; unsigned int data[16]; /* Create a simple polling list for analog input channel 0 */ diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 7517001fb8f0..3e51476a7045 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -1672,9 +1672,6 @@ static int std_req_set_configuration(struct nbu2ss_udc *udc) /*-------------------------------------------------------------------------*/ static inline void _nbu2ss_read_request_data(struct nbu2ss_udc *udc, u32 *pdata) { - if ((!udc) && (!pdata)) - return; - *pdata = _nbu2ss_readl(&udc->p_regs->SETUP_DATA0); pdata++; *pdata = _nbu2ss_readl(&udc->p_regs->SETUP_DATA1); @@ -2686,7 +2683,7 @@ static int nbu2ss_ep_queue( if (req->unaligned) { if (!ep->virt_buf) - ep->virt_buf = (u8 *)dma_alloc_coherent( + ep->virt_buf = dma_alloc_coherent( NULL, PAGE_SIZE, &ep->phys_buf, GFP_ATOMIC | GFP_DMA); if (ep->epnum > 0) { @@ -2941,11 +2938,6 @@ static int nbu2ss_gad_get_frame(struct usb_gadget *pgadget) } udc = container_of(pgadget, struct nbu2ss_udc, gadget); - if (!udc) { - dev_err(&pgadget->dev, "%s, udc == NULL\n", __func__); - return -EINVAL; - } - data = gpio_get_value(VBUS_VALUE); if (data == 0) return -EINVAL; diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig index dfff675b3055..bbb7af551696 100644 --- a/drivers/staging/fsl-dpaa2/Kconfig +++ b/drivers/staging/fsl-dpaa2/Kconfig @@ -4,7 +4,7 @@ config FSL_DPAA2 bool "Freescale DPAA2 devices" - depends on FSL_MC_BUS && ARCH_LAYERSCAPE + depends on FSL_MC_BUS ---help--- Build drivers for Freescale DataPath Acceleration Architecture (DPAA2) family of SoCs. @@ -16,3 +16,11 @@ config FSL_DPAA2_ETH ---help--- Ethernet driver for Freescale DPAA2 SoCs, using the Freescale MC bus driver + +config FSL_DPAA2_ETHSW + tristate "Freescale DPAA2 Ethernet Switch" + depends on FSL_DPAA2 + depends on NET_SWITCHDEV + ---help--- + Driver for Freescale DPAA2 Ethernet Switch. Select + BRIDGE to have support for bridge tools. diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile index 0836ba8977b1..6cfd76b29970 100644 --- a/drivers/staging/fsl-dpaa2/Makefile +++ b/drivers/staging/fsl-dpaa2/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/ +obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/ diff --git a/drivers/staging/fsl-dpaa2/ethernet/README b/drivers/staging/fsl-dpaa2/ethernet/README index 410952ecf657..e3b5c90197e4 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/README +++ b/drivers/staging/fsl-dpaa2/ethernet/README @@ -36,7 +36,7 @@ are treated as internal resources of other objects. For a more detailed description of the DPAA2 architecture and its object abstractions see: - drivers/staging/fsl-mc/README.txt + Documentation/networking/dpaa2/overview.rst Each Linux net device is built on top of a Datapath Network Interface (DPNI) object and uses Buffer Pools (DPBPs), I/O Portals (DPIOs) and Concentrators diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index 2817e67df3d5..553678d8b2eb 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -39,7 +39,7 @@ #include <linux/kthread.h> #include <linux/iommu.h> -#include "../../fsl-mc/include/mc.h" +#include <linux/fsl/mc.h> #include "dpaa2-eth.h" /* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files @@ -324,7 +324,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch) } fd = dpaa2_dq_fd(dq); - fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq); + fq = (struct dpaa2_eth_fq *)(uintptr_t)dpaa2_dq_fqd_ctx(dq); fq->stats.frames++; fq->consume(priv, ch, fd, &ch->napi, fq->flowid); @@ -373,13 +373,15 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv, /* Prepare the HW SGT structure */ sgt_buf_size = priv->tx_data_offset + - sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs); - sgt_buf = kzalloc(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN, GFP_ATOMIC); + sizeof(struct dpaa2_sg_entry) * num_dma_bufs; + sgt_buf = netdev_alloc_frag(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN); if (unlikely(!sgt_buf)) { err = -ENOMEM; goto sgt_buf_alloc_failed; } sgt_buf = PTR_ALIGN(sgt_buf, DPAA2_ETH_TX_BUF_ALIGN); + memset(sgt_buf, 0, sgt_buf_size); + sgt = (struct dpaa2_sg_entry *)(sgt_buf + priv->tx_data_offset); /* Fill in the HW SGT structure. @@ -404,7 +406,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv, swa->skb = skb; swa->scl = scl; swa->num_sg = num_sg; - swa->num_dma_bufs = num_dma_bufs; + swa->sgt_size = sgt_buf_size; /* Separately map the SGT buffer */ addr = dma_map_single(dev, sgt_buf, sgt_buf_size, DMA_BIDIRECTIONAL); @@ -421,7 +423,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv, return 0; dma_map_single_failed: - kfree(sgt_buf); + skb_free_frag(sgt_buf); sgt_buf_alloc_failed: dma_unmap_sg(dev, scl, num_sg, DMA_BIDIRECTIONAL); dma_map_sg_failed: @@ -487,9 +489,6 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv, dma_addr_t fd_addr; struct sk_buff **skbh, *skb; unsigned char *buffer_start; - int unmap_size; - struct scatterlist *scl; - int num_sg, num_dma_bufs; struct dpaa2_eth_swa *swa; u8 fd_format = dpaa2_fd_get_format(fd); @@ -508,26 +507,22 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv, } else if (fd_format == dpaa2_fd_sg) { swa = (struct dpaa2_eth_swa *)skbh; skb = swa->skb; - scl = swa->scl; - num_sg = swa->num_sg; - num_dma_bufs = swa->num_dma_bufs; /* Unmap the scatterlist */ - dma_unmap_sg(dev, scl, num_sg, DMA_BIDIRECTIONAL); - kfree(scl); + dma_unmap_sg(dev, swa->scl, swa->num_sg, DMA_BIDIRECTIONAL); + kfree(swa->scl); /* Unmap the SGT buffer */ - unmap_size = priv->tx_data_offset + - sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs); - dma_unmap_single(dev, fd_addr, unmap_size, DMA_BIDIRECTIONAL); + dma_unmap_single(dev, fd_addr, swa->sgt_size, + DMA_BIDIRECTIONAL); } else { netdev_dbg(priv->net_dev, "Invalid FD format\n"); return; } - /* Free SGT buffer kmalloc'ed on tx */ + /* Free SGT buffer allocated on tx */ if (fd_format != dpaa2_fd_single) - kfree(skbh); + skb_free_frag(skbh); /* Move on with skb release */ dev_kfree_skb(skb); @@ -1844,6 +1839,21 @@ static int setup_dpni(struct fsl_mc_device *ls_dev) return err; } + /* Check if we can work with this DPNI object */ + err = dpni_get_api_version(priv->mc_io, 0, &priv->dpni_ver_major, + &priv->dpni_ver_minor); + if (err) { + dev_err(dev, "dpni_get_api_version() failed\n"); + goto close; + } + if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_VER_MAJOR, DPNI_VER_MINOR) < 0) { + dev_err(dev, "DPNI version %u.%u not supported, need >= %u.%u\n", + priv->dpni_ver_major, priv->dpni_ver_minor, + DPNI_VER_MAJOR, DPNI_VER_MINOR); + err = -ENOTSUPP; + goto close; + } + ls_dev->mc_io = priv->mc_io; ls_dev->mc_handle = priv->mc_token; @@ -1864,7 +1874,6 @@ static int setup_dpni(struct fsl_mc_device *ls_dev) if (err) goto close; - return 0; close: @@ -1906,7 +1915,7 @@ static int setup_rx_flow(struct dpaa2_eth_priv *priv, queue.destination.id = fq->channel->dpcon_id; queue.destination.type = DPNI_DEST_DPCON; queue.destination.priority = 1; - queue.user_context = (u64)fq; + queue.user_context = (u64)(uintptr_t)fq; err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_RX, 0, fq->flowid, DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST, @@ -1958,7 +1967,7 @@ static int setup_tx_flow(struct dpaa2_eth_priv *priv, queue.destination.id = fq->channel->dpcon_id; queue.destination.type = DPNI_DEST_DPCON; queue.destination.priority = 0; - queue.user_context = (u64)fq; + queue.user_context = (u64)(uintptr_t)fq; err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_TX_CONFIRM, 0, fq->flowid, DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST, @@ -2316,11 +2325,6 @@ static int poll_link_state(void *arg) return 0; } -static irqreturn_t dpni_irq0_handler(int irq_num, void *arg) -{ - return IRQ_WAKE_THREAD; -} - static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) { u32 status = ~0; @@ -2355,8 +2359,7 @@ static int setup_irqs(struct fsl_mc_device *ls_dev) irq = ls_dev->irqs[0]; err = devm_request_threaded_irq(&ls_dev->dev, irq->msi_desc->irq, - dpni_irq0_handler, - dpni_irq0_handler_thread, + NULL, dpni_irq0_handler_thread, IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(&ls_dev->dev), &ls_dev->dev); if (err < 0) { @@ -2440,7 +2443,10 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) err = fsl_mc_portal_allocate(dpni_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &priv->mc_io); if (err) { - dev_err(dev, "MC portal allocation failed\n"); + if (err == -ENXIO) + err = -EPROBE_DEFER; + else + dev_err(dev, "MC portal allocation failed\n"); goto err_portal_alloc; } @@ -2552,7 +2558,6 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) priv = netdev_priv(net_dev); unregister_netdev(net_dev); - dev_info(net_dev->dev.parent, "Removed interface %s\n", net_dev->name); if (priv->do_link_poll) kthread_stop(priv->poll_thread); @@ -2573,6 +2578,8 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) dev_set_drvdata(dev, NULL); free_netdev(net_dev); + dev_dbg(net_dev->dev.parent, "Removed interface %s\n", net_dev->name); + return 0; } diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h index e577410fdf4f..54cea2fc6e58 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h @@ -35,11 +35,10 @@ #include <linux/netdevice.h> #include <linux/if_vlan.h> +#include <linux/fsl/mc.h> #include "../../fsl-mc/include/dpaa2-io.h" #include "../../fsl-mc/include/dpaa2-fd.h" -#include "../../fsl-mc/include/dpbp.h" -#include "../../fsl-mc/include/dpcon.h" #include "dpni.h" #include "dpni-cmd.h" @@ -109,7 +108,7 @@ struct dpaa2_eth_swa { struct sk_buff *skb; struct scatterlist *scl; int num_sg; - int num_dma_bufs; + int sgt_size; }; /* Annotation valid bits in FD FRC */ @@ -143,7 +142,7 @@ struct dpaa2_fas { u8 ppid; __le16 ifpid; __le32 status; -} __packed; +}; /* Frame annotation status word is located in the first 8 bytes * of the buffer's hardware annoatation area @@ -252,11 +251,11 @@ struct dpaa2_eth_ch_stats { /* Maximum number of queues associated with a DPNI */ #define DPAA2_ETH_MAX_RX_QUEUES 16 -#define DPAA2_ETH_MAX_TX_QUEUES NR_CPUS +#define DPAA2_ETH_MAX_TX_QUEUES 16 #define DPAA2_ETH_MAX_QUEUES (DPAA2_ETH_MAX_RX_QUEUES + \ DPAA2_ETH_MAX_TX_QUEUES) -#define DPAA2_ETH_MAX_DPCONS NR_CPUS +#define DPAA2_ETH_MAX_DPCONS 16 enum dpaa2_eth_fq_type { DPAA2_RX_FQ = 0, @@ -286,7 +285,6 @@ struct dpaa2_eth_channel { struct fsl_mc_device *dpcon; int dpcon_id; int ch_id; - int dpio_id; struct napi_struct napi; struct dpaa2_io *dpio; struct dpaa2_io_store *store; @@ -313,6 +311,8 @@ struct dpaa2_eth_priv { struct dpaa2_eth_channel *channel[DPAA2_ETH_MAX_DPCONS]; struct dpni_attr dpni_attrs; + u16 dpni_ver_major; + u16 dpni_ver_minor; u16 tx_data_offset; struct fsl_mc_device *dpbp_dev; @@ -356,6 +356,14 @@ struct dpaa2_eth_priv { extern const struct ethtool_ops dpaa2_ethtool_ops; extern const char dpaa2_eth_drv_version[]; +static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv, + u16 ver_major, u16 ver_minor) +{ + if (priv->dpni_ver_major == ver_major) + return priv->dpni_ver_minor - ver_minor; + return priv->dpni_ver_major - ver_major; +} + /* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but the skb built around * the buffer also needs space for its shared info struct, and we need * to allocate enough to accommodate hardware alignment restrictions diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c index 070a3f2a0523..bfc8b64169ca 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c @@ -78,20 +78,13 @@ static void dpaa2_eth_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *drvinfo) { struct dpaa2_eth_priv *priv = netdev_priv(net_dev); - u16 fw_major, fw_minor; - int err; strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); strlcpy(drvinfo->version, dpaa2_eth_drv_version, sizeof(drvinfo->version)); - err = dpni_get_api_version(priv->mc_io, 0, &fw_major, &fw_minor); - if (!err) - snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), - "%u.%u", fw_major, fw_minor); - else - strlcpy(drvinfo->fw_version, "N/A", - sizeof(drvinfo->fw_version)); + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), + "%u.%u", priv->dpni_ver_major, priv->dpni_ver_minor); strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent), sizeof(drvinfo->bus_info)); @@ -126,6 +119,8 @@ out: return err; } +#define DPNI_DYNAMIC_LINK_SET_VER_MAJOR 7 +#define DPNI_DYNAMIC_LINK_SET_VER_MINOR 1 static int dpaa2_eth_set_link_ksettings(struct net_device *net_dev, const struct ethtool_link_ksettings *link_settings) @@ -134,15 +129,16 @@ dpaa2_eth_set_link_ksettings(struct net_device *net_dev, struct dpaa2_eth_priv *priv = netdev_priv(net_dev); int err = 0; - netdev_dbg(net_dev, "Setting link parameters..."); - - /* Due to a temporary MC limitation, the DPNI must be down + /* If using an older MC version, the DPNI must be down * in order to be able to change link settings. Taking steps to let * the user know that. */ - if (netif_running(net_dev)) { - netdev_info(net_dev, "Sorry, interface must be brought down first.\n"); - return -EACCES; + if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_DYNAMIC_LINK_SET_VER_MAJOR, + DPNI_DYNAMIC_LINK_SET_VER_MINOR) < 0) { + if (netif_running(net_dev)) { + netdev_info(net_dev, "Interface must be brought down first.\n"); + return -EACCES; + } } cfg.rate = link_settings->base.speed; diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h b/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h index 3120e22496d0..d6f96f302cc6 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h +++ b/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h @@ -539,8 +539,8 @@ struct dpni_rsp_get_taildrop { }; struct dpni_rsp_get_api_version { - u16 major; - u16 minor; + __le16 major; + __le16 minor; }; #endif /* _FSL_DPNI_CMD_H */ diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.c b/drivers/staging/fsl-dpaa2/ethernet/dpni.c index e8be76181c36..1a721c95a67a 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpni.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpni.c @@ -32,7 +32,7 @@ */ #include <linux/kernel.h> #include <linux/errno.h> -#include "../../fsl-mc/include/mc.h" +#include <linux/fsl/mc.h> #include "dpni.h" #include "dpni-cmd.h" @@ -122,7 +122,7 @@ int dpni_open(struct fsl_mc_io *mc_io, int dpni_id, u16 *token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_open *cmd_params; int err; @@ -160,7 +160,7 @@ int dpni_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE, @@ -188,7 +188,7 @@ int dpni_set_pools(struct fsl_mc_io *mc_io, u16 token, const struct dpni_pools_cfg *cfg) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_pools *cmd_params; int i; @@ -222,7 +222,7 @@ int dpni_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE, @@ -245,7 +245,7 @@ int dpni_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE, @@ -270,7 +270,7 @@ int dpni_is_enabled(struct fsl_mc_io *mc_io, u16 token, int *en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_is_enabled *rsp_params; int err; @@ -303,7 +303,7 @@ int dpni_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET, @@ -335,7 +335,7 @@ int dpni_set_irq_enable(struct fsl_mc_io *mc_io, u8 irq_index, u8 en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_irq_enable *cmd_params; /* prepare command */ @@ -366,7 +366,7 @@ int dpni_get_irq_enable(struct fsl_mc_io *mc_io, u8 irq_index, u8 *en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_irq_enable *cmd_params; struct dpni_rsp_get_irq_enable *rsp_params; @@ -413,7 +413,7 @@ int dpni_set_irq_mask(struct fsl_mc_io *mc_io, u8 irq_index, u32 mask) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_irq_mask *cmd_params; /* prepare command */ @@ -447,7 +447,7 @@ int dpni_get_irq_mask(struct fsl_mc_io *mc_io, u8 irq_index, u32 *mask) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_irq_mask *cmd_params; struct dpni_rsp_get_irq_mask *rsp_params; int err; @@ -489,7 +489,7 @@ int dpni_get_irq_status(struct fsl_mc_io *mc_io, u8 irq_index, u32 *status) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_irq_status *cmd_params; struct dpni_rsp_get_irq_status *rsp_params; int err; @@ -532,7 +532,7 @@ int dpni_clear_irq_status(struct fsl_mc_io *mc_io, u8 irq_index, u32 status) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_clear_irq_status *cmd_params; /* prepare command */ @@ -561,7 +561,7 @@ int dpni_get_attributes(struct fsl_mc_io *mc_io, u16 token, struct dpni_attr *attr) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_attr *rsp_params; int err; @@ -609,7 +609,7 @@ int dpni_set_errors_behavior(struct fsl_mc_io *mc_io, u16 token, struct dpni_error_cfg *cfg) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_errors_behavior *cmd_params; /* prepare command */ @@ -641,7 +641,7 @@ int dpni_get_buffer_layout(struct fsl_mc_io *mc_io, enum dpni_queue_type qtype, struct dpni_buffer_layout *layout) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_buffer_layout *cmd_params; struct dpni_rsp_get_buffer_layout *rsp_params; int err; @@ -689,7 +689,7 @@ int dpni_set_buffer_layout(struct fsl_mc_io *mc_io, enum dpni_queue_type qtype, const struct dpni_buffer_layout *layout) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_buffer_layout *cmd_params; /* prepare command */ @@ -731,7 +731,7 @@ int dpni_set_offload(struct fsl_mc_io *mc_io, enum dpni_offload type, u32 config) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_offload *cmd_params; cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_OFFLOAD, @@ -750,7 +750,7 @@ int dpni_get_offload(struct fsl_mc_io *mc_io, enum dpni_offload type, u32 *config) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_offload *cmd_params; struct dpni_rsp_get_offload *rsp_params; int err; @@ -792,7 +792,7 @@ int dpni_get_qdid(struct fsl_mc_io *mc_io, enum dpni_queue_type qtype, u16 *qdid) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_qdid *cmd_params; struct dpni_rsp_get_qdid *rsp_params; int err; @@ -830,7 +830,7 @@ int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, u16 token, u16 *data_offset) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_tx_data_offset *rsp_params; int err; @@ -865,7 +865,7 @@ int dpni_set_link_cfg(struct fsl_mc_io *mc_io, u16 token, const struct dpni_link_cfg *cfg) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_link_cfg *cmd_params; /* prepare command */ @@ -894,7 +894,7 @@ int dpni_get_link_state(struct fsl_mc_io *mc_io, u16 token, struct dpni_link_state *state) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_link_state *rsp_params; int err; @@ -933,7 +933,7 @@ int dpni_set_max_frame_length(struct fsl_mc_io *mc_io, u16 token, u16 max_frame_length) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_max_frame_length *cmd_params; /* prepare command */ @@ -963,7 +963,7 @@ int dpni_get_max_frame_length(struct fsl_mc_io *mc_io, u16 token, u16 *max_frame_length) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_max_frame_length *rsp_params; int err; @@ -998,7 +998,7 @@ int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io, u16 token, int en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_multicast_promisc *cmd_params; /* prepare command */ @@ -1026,7 +1026,7 @@ int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io, u16 token, int *en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_multicast_promisc *rsp_params; int err; @@ -1061,7 +1061,7 @@ int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io, u16 token, int en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_unicast_promisc *cmd_params; /* prepare command */ @@ -1089,7 +1089,7 @@ int dpni_get_unicast_promisc(struct fsl_mc_io *mc_io, u16 token, int *en) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_unicast_promisc *rsp_params; int err; @@ -1124,7 +1124,7 @@ int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io, u16 token, const u8 mac_addr[6]) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_primary_mac_addr *cmd_params; int i; @@ -1154,7 +1154,7 @@ int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, u16 token, u8 mac_addr[6]) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_primary_mac_addr *rsp_params; int i, err; @@ -1193,7 +1193,7 @@ int dpni_get_port_mac_addr(struct fsl_mc_io *mc_io, u16 token, u8 mac_addr[6]) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_rsp_get_port_mac_addr *rsp_params; int i, err; @@ -1229,7 +1229,7 @@ int dpni_add_mac_addr(struct fsl_mc_io *mc_io, u16 token, const u8 mac_addr[6]) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_add_mac_addr *cmd_params; int i; @@ -1259,7 +1259,7 @@ int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, u16 token, const u8 mac_addr[6]) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_remove_mac_addr *cmd_params; int i; @@ -1293,7 +1293,7 @@ int dpni_clear_mac_filters(struct fsl_mc_io *mc_io, int unicast, int multicast) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_clear_mac_filters *cmd_params; /* prepare command */ @@ -1327,7 +1327,7 @@ int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, u8 tc_id, const struct dpni_rx_tc_dist_cfg *cfg) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_rx_tc_dist *cmd_params; /* prepare command */ @@ -1371,7 +1371,7 @@ int dpni_set_queue(struct fsl_mc_io *mc_io, u8 options, const struct dpni_queue *queue) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_queue *cmd_params; /* prepare command */ @@ -1419,7 +1419,7 @@ int dpni_get_queue(struct fsl_mc_io *mc_io, struct dpni_queue *queue, struct dpni_queue_id *qid) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_queue *cmd_params; struct dpni_rsp_get_queue *rsp_params; int err; @@ -1473,7 +1473,7 @@ int dpni_get_statistics(struct fsl_mc_io *mc_io, u8 page, union dpni_statistics *stat) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_statistics *cmd_params; struct dpni_rsp_get_statistics *rsp_params; int i, err; @@ -1522,7 +1522,7 @@ int dpni_set_taildrop(struct fsl_mc_io *mc_io, u8 index, struct dpni_taildrop *taildrop) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_set_taildrop *cmd_params; /* prepare command */ @@ -1566,7 +1566,7 @@ int dpni_get_taildrop(struct fsl_mc_io *mc_io, u8 index, struct dpni_taildrop *taildrop) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpni_cmd_get_taildrop *cmd_params; struct dpni_rsp_get_taildrop *rsp_params; int err; @@ -1610,7 +1610,7 @@ int dpni_get_api_version(struct fsl_mc_io *mc_io, u16 *minor_ver) { struct dpni_rsp_get_api_version *rsp_params; - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; int err; cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_API_VERSION, diff --git a/drivers/staging/fsl-dpaa2/ethsw/Makefile b/drivers/staging/fsl-dpaa2/ethsw/Makefile new file mode 100644 index 000000000000..f6f2cf798faf --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the Freescale DPAA2 Ethernet Switch +# +# Copyright 2014-2017 Freescale Semiconductor Inc. +# Copyright 2017-2018 NXP + +obj-$(CONFIG_FSL_DPAA2_ETHSW) += dpaa2-ethsw.o + +dpaa2-ethsw-objs := ethsw.o ethsw-ethtool.o dpsw.o diff --git a/drivers/staging/fsl-dpaa2/ethsw/README b/drivers/staging/fsl-dpaa2/ethsw/README new file mode 100644 index 000000000000..f6fc07f780d1 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/README @@ -0,0 +1,106 @@ +DPAA2 Ethernet Switch driver +============================ + +This file provides documentation for the DPAA2 Ethernet Switch driver + + +Contents +======== + Supported Platforms + Architecture Overview + Creating an Ethernet Switch + Features + + + Supported Platforms +=================== +This driver provides networking support for Freescale LS2085A, LS2088A +DPAA2 SoCs. + + +Architecture Overview +===================== +The Ethernet Switch in the DPAA2 architecture consists of several hardware +resources that provide the functionality. These are allocated and +configured via the Management Complex (MC) portals. MC abstracts most of +these resources as DPAA2 objects and exposes ABIs through which they can +be configured and controlled. + +For a more detailed description of the DPAA2 architecture and its object +abstractions see: + drivers/staging/fsl-mc/README.txt + +The Ethernet Switch is built on top of a Datapath Switch (DPSW) object. + +Configuration interface: + + --------------------- + | DPAA2 Switch driver | + --------------------- + . + . + ---------- + | DPSW API | + ---------- + . software + ================= . ============== + . hardware + --------------------- + | MC hardware portals | + --------------------- + . + . + ------ + | DPSW | + ------ + +Driver uses the switch device driver model and exposes each switch port as +a network interface, which can be included in a bridge. Traffic switched +between ports is offloaded into the hardware. Exposed network interfaces +are not used for I/O, they are used just for configuration. This +limitation is going to be addressed in the future. + +The DPSW can have ports connected to DPNIs or to PHYs via DPMACs. + + + [ethA] [ethB] [ethC] [ethD] [ethE] [ethF] + : : : : : : + : : : : : : +[eth drv] [eth drv] [ ethsw drv ] + : : : : : : kernel +======================================================================== + : : : : : : hardware + [DPNI] [DPNI] [============= DPSW =================] + | | | | | | + | ---------- | [DPMAC] [DPMAC] + ------------------------------- | | + | | + [PHY] [PHY] + +For a more detailed description of the Ethernet switch device driver model +see: + Documentation/networking/switchdev.txt + +Creating an Ethernet Switch +=========================== +A device is created for the switch objects probed on the MC bus. Each DPSW +has a number of properties which determine the configuration options and +associated hardware resources. + +A DPSW object (and the other DPAA2 objects needed for a DPAA2 switch) can +be added to a container on the MC bus in one of two ways: statically, +through a Datapath Layout Binary file (DPL) that is parsed by MC at boot +time; or created dynamically at runtime, via the DPAA2 objects APIs. + +Features +======== +Driver configures DPSW to perform hardware switching offload of +unicast/multicast/broadcast (VLAN tagged or untagged) traffic between its +ports. + +It allows configuration of hardware learning, flooding, multicast groups, +port VLAN configuration and STP state. + +Static entries can be added/removed from the FDB. + +Hardware statistics for each port are provided through ethtool -S option. diff --git a/drivers/staging/fsl-dpaa2/ethsw/TODO b/drivers/staging/fsl-dpaa2/ethsw/TODO new file mode 100644 index 000000000000..24b5e95a96f8 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/TODO @@ -0,0 +1,14 @@ +* Add I/O capabilities on switch port netdevices. This will allow control +traffic to reach the CPU. +* Add ACL to redirect control traffic to CPU. +* Add support for displaying learned FDB entries +* Add support for multiple FDBs and switch port partitioning +* MC firmware uprev; the DPAA2 objects used by the Ethernet Switch driver +need to be kept in sync with binary interface changes in MC +* refine README file +* cleanup + +NOTE: At least first three of the above are required before getting the +DPAA2 Ethernet Switch driver out of staging. Another requirement is that +dpio driver is moved to drivers/soc (this is required for I/O). + diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h new file mode 100644 index 000000000000..1c203e6e8035 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + * + */ + +#ifndef __FSL_DPSW_CMD_H +#define __FSL_DPSW_CMD_H + +/* DPSW Version */ +#define DPSW_VER_MAJOR 8 +#define DPSW_VER_MINOR 0 + +#define DPSW_CMD_BASE_VERSION 1 +#define DPSW_CMD_ID_OFFSET 4 + +#define DPSW_CMD_ID(id) (((id) << DPSW_CMD_ID_OFFSET) | DPSW_CMD_BASE_VERSION) + +/* Command IDs */ +#define DPSW_CMDID_CLOSE DPSW_CMD_ID(0x800) +#define DPSW_CMDID_OPEN DPSW_CMD_ID(0x802) + +#define DPSW_CMDID_GET_API_VERSION DPSW_CMD_ID(0xa02) + +#define DPSW_CMDID_ENABLE DPSW_CMD_ID(0x002) +#define DPSW_CMDID_DISABLE DPSW_CMD_ID(0x003) +#define DPSW_CMDID_GET_ATTR DPSW_CMD_ID(0x004) +#define DPSW_CMDID_RESET DPSW_CMD_ID(0x005) + +#define DPSW_CMDID_SET_IRQ_ENABLE DPSW_CMD_ID(0x012) + +#define DPSW_CMDID_SET_IRQ_MASK DPSW_CMD_ID(0x014) + +#define DPSW_CMDID_GET_IRQ_STATUS DPSW_CMD_ID(0x016) +#define DPSW_CMDID_CLEAR_IRQ_STATUS DPSW_CMD_ID(0x017) + +#define DPSW_CMDID_IF_SET_TCI DPSW_CMD_ID(0x030) +#define DPSW_CMDID_IF_SET_STP DPSW_CMD_ID(0x031) + +#define DPSW_CMDID_IF_GET_COUNTER DPSW_CMD_ID(0x034) + +#define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D) +#define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E) + +#define DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH DPSW_CMD_ID(0x044) + +#define DPSW_CMDID_IF_GET_LINK_STATE DPSW_CMD_ID(0x046) +#define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047) +#define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048) + +#define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C) + +#define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060) +#define DPSW_CMDID_VLAN_ADD_IF DPSW_CMD_ID(0x061) +#define DPSW_CMDID_VLAN_ADD_IF_UNTAGGED DPSW_CMD_ID(0x062) + +#define DPSW_CMDID_VLAN_REMOVE_IF DPSW_CMD_ID(0x064) +#define DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED DPSW_CMD_ID(0x065) +#define DPSW_CMDID_VLAN_REMOVE_IF_FLOODING DPSW_CMD_ID(0x066) +#define DPSW_CMDID_VLAN_REMOVE DPSW_CMD_ID(0x067) + +#define DPSW_CMDID_FDB_ADD_UNICAST DPSW_CMD_ID(0x084) +#define DPSW_CMDID_FDB_REMOVE_UNICAST DPSW_CMD_ID(0x085) +#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086) +#define DPSW_CMDID_FDB_REMOVE_MULTICAST DPSW_CMD_ID(0x087) +#define DPSW_CMDID_FDB_SET_LEARNING_MODE DPSW_CMD_ID(0x088) + +/* Macros for accessing command fields smaller than 1byte */ +#define DPSW_MASK(field) \ + GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \ + DPSW_##field##_SHIFT) +#define dpsw_set_field(var, field, val) \ + ((var) |= (((val) << DPSW_##field##_SHIFT) & DPSW_MASK(field))) +#define dpsw_get_field(var, field) \ + (((var) & DPSW_MASK(field)) >> DPSW_##field##_SHIFT) +#define dpsw_get_bit(var, bit) \ + (((var) >> (bit)) & GENMASK(0, 0)) + +struct dpsw_cmd_open { + __le32 dpsw_id; +}; + +#define DPSW_COMPONENT_TYPE_SHIFT 0 +#define DPSW_COMPONENT_TYPE_SIZE 4 + +struct dpsw_cmd_create { + /* cmd word 0 */ + __le16 num_ifs; + u8 max_fdbs; + u8 max_meters_per_if; + /* from LSB: only the first 4 bits */ + u8 component_type; + u8 pad[3]; + /* cmd word 1 */ + __le16 max_vlans; + __le16 max_fdb_entries; + __le16 fdb_aging_time; + __le16 max_fdb_mc_groups; + /* cmd word 2 */ + __le64 options; +}; + +struct dpsw_cmd_destroy { + __le32 dpsw_id; +}; + +#define DPSW_ENABLE_SHIFT 0 +#define DPSW_ENABLE_SIZE 1 + +struct dpsw_rsp_is_enabled { + /* from LSB: enable:1 */ + u8 enabled; +}; + +struct dpsw_cmd_set_irq_enable { + u8 enable_state; + u8 pad[3]; + u8 irq_index; +}; + +struct dpsw_cmd_get_irq_enable { + __le32 pad; + u8 irq_index; +}; + +struct dpsw_rsp_get_irq_enable { + u8 enable_state; +}; + +struct dpsw_cmd_set_irq_mask { + __le32 mask; + u8 irq_index; +}; + +struct dpsw_cmd_get_irq_mask { + __le32 pad; + u8 irq_index; +}; + +struct dpsw_rsp_get_irq_mask { + __le32 mask; +}; + +struct dpsw_cmd_get_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dpsw_rsp_get_irq_status { + __le32 status; +}; + +struct dpsw_cmd_clear_irq_status { + __le32 status; + u8 irq_index; +}; + +#define DPSW_COMPONENT_TYPE_SHIFT 0 +#define DPSW_COMPONENT_TYPE_SIZE 4 + +struct dpsw_rsp_get_attr { + /* cmd word 0 */ + __le16 num_ifs; + u8 max_fdbs; + u8 num_fdbs; + __le16 max_vlans; + __le16 num_vlans; + /* cmd word 1 */ + __le16 max_fdb_entries; + __le16 fdb_aging_time; + __le32 dpsw_id; + /* cmd word 2 */ + __le16 mem_size; + __le16 max_fdb_mc_groups; + u8 max_meters_per_if; + /* from LSB only the first 4 bits */ + u8 component_type; + __le16 pad; + /* cmd word 3 */ + __le64 options; +}; + +struct dpsw_cmd_if_set_flooding { + __le16 if_id; + /* from LSB: enable:1 */ + u8 enable; +}; + +struct dpsw_cmd_if_set_broadcast { + __le16 if_id; + /* from LSB: enable:1 */ + u8 enable; +}; + +#define DPSW_VLAN_ID_SHIFT 0 +#define DPSW_VLAN_ID_SIZE 12 +#define DPSW_DEI_SHIFT 12 +#define DPSW_DEI_SIZE 1 +#define DPSW_PCP_SHIFT 13 +#define DPSW_PCP_SIZE 3 + +struct dpsw_cmd_if_set_tci { + __le16 if_id; + /* from LSB: VLAN_ID:12 DEI:1 PCP:3 */ + __le16 conf; +}; + +#define DPSW_STATE_SHIFT 0 +#define DPSW_STATE_SIZE 4 + +struct dpsw_cmd_if_set_stp { + __le16 if_id; + __le16 vlan_id; + /* only the first LSB 4 bits */ + u8 state; +}; + +#define DPSW_COUNTER_TYPE_SHIFT 0 +#define DPSW_COUNTER_TYPE_SIZE 5 + +struct dpsw_cmd_if_get_counter { + __le16 if_id; + /* from LSB: type:5 */ + u8 type; +}; + +struct dpsw_rsp_if_get_counter { + __le64 pad; + __le64 counter; +}; + +struct dpsw_cmd_if { + __le16 if_id; +}; + +struct dpsw_cmd_if_set_max_frame_length { + __le16 if_id; + __le16 frame_length; +}; + +struct dpsw_cmd_if_set_link_cfg { + /* cmd word 0 */ + __le16 if_id; + u8 pad[6]; + /* cmd word 1 */ + __le32 rate; + __le32 pad1; + /* cmd word 2 */ + __le64 options; +}; + +struct dpsw_cmd_if_get_link_state { + __le16 if_id; +}; + +#define DPSW_UP_SHIFT 0 +#define DPSW_UP_SIZE 1 + +struct dpsw_rsp_if_get_link_state { + /* cmd word 0 */ + __le32 pad0; + u8 up; + u8 pad1[3]; + /* cmd word 1 */ + __le32 rate; + __le32 pad2; + /* cmd word 2 */ + __le64 options; +}; + +struct dpsw_vlan_add { + __le16 fdb_id; + __le16 vlan_id; +}; + +struct dpsw_cmd_vlan_manage_if { + /* cmd word 0 */ + __le16 pad0; + __le16 vlan_id; + __le32 pad1; + /* cmd word 1-4 */ + __le64 if_id[4]; +}; + +struct dpsw_cmd_vlan_remove { + __le16 pad; + __le16 vlan_id; +}; + +struct dpsw_cmd_fdb_add { + __le32 pad; + __le16 fdb_aging_time; + __le16 num_fdb_entries; +}; + +struct dpsw_rsp_fdb_add { + __le16 fdb_id; +}; + +struct dpsw_cmd_fdb_remove { + __le16 fdb_id; +}; + +#define DPSW_ENTRY_TYPE_SHIFT 0 +#define DPSW_ENTRY_TYPE_SIZE 4 + +struct dpsw_cmd_fdb_unicast_op { + /* cmd word 0 */ + __le16 fdb_id; + u8 mac_addr[6]; + /* cmd word 1 */ + __le16 if_egress; + /* only the first 4 bits from LSB */ + u8 type; +}; + +struct dpsw_cmd_fdb_multicast_op { + /* cmd word 0 */ + __le16 fdb_id; + __le16 num_ifs; + /* only the first 4 bits from LSB */ + u8 type; + u8 pad[3]; + /* cmd word 1 */ + u8 mac_addr[6]; + __le16 pad2; + /* cmd word 2-5 */ + __le64 if_id[4]; +}; + +#define DPSW_LEARNING_MODE_SHIFT 0 +#define DPSW_LEARNING_MODE_SIZE 4 + +struct dpsw_cmd_fdb_set_learning_mode { + __le16 fdb_id; + /* only the first 4 bits from LSB */ + u8 mode; +}; + +struct dpsw_rsp_get_api_version { + __le16 version_major; + __le16 version_minor; +}; + +#endif /* __FSL_DPSW_CMD_H */ diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c new file mode 100644 index 000000000000..9b9bc604b461 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c @@ -0,0 +1,1123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + * + */ + +#include <linux/fsl/mc.h> +#include "dpsw.h" +#include "dpsw-cmd.h" + +static void build_if_id_bitmap(__le64 *bmap, + const u16 *id, + const u16 num_ifs) +{ + int i; + + for (i = 0; (i < num_ifs) && (i < DPSW_MAX_IF); i++) { + if (id[i] < DPSW_MAX_IF) + bmap[id[i] / 64] |= cpu_to_le64(BIT_MASK(id[i] % 64)); + } +} + +/** + * dpsw_open() - Open a control session for the specified object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpsw_id: DPSW unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpsw_create() function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dpsw_id, + u16 *token) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_open *cmd_params; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_OPEN, + cmd_flags, + 0); + cmd_params = (struct dpsw_cmd_open *)cmd.params; + cmd_params->dpsw_id = cpu_to_le32(dpsw_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = mc_cmd_hdr_read_token(&cmd); + + return 0; +} + +/** + * dpsw_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLOSE, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_enable() - Enable DPSW functionality + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_ENABLE, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_disable() - Disable DPSW functionality + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_DISABLE, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_reset() - Reset the DPSW, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_RESET, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_set_irq_enable() - Set overall interrupt state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPCI object + * @irq_index: The interrupt index to configure + * @en: Interrupt state - enable = 1, disable = 0 + * + * Allows GPP software to control when interrupts are generated. + * Each interrupt can have up to 32 causes. The enable/disable control's the + * overall interrupt state. if the interrupt is disabled no causes will cause + * an interrupt + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u8 en) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_set_irq_enable *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_ENABLE, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_set_irq_enable *)cmd.params; + dpsw_set_field(cmd_params->enable_state, ENABLE, en); + cmd_params->irq_index = irq_index; + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_set_irq_mask() - Set interrupt mask. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPCI object + * @irq_index: The interrupt index to configure + * @mask: Event mask to trigger interrupt; + * each bit: + * 0 = ignore event + * 1 = consider event for asserting IRQ + * + * Every interrupt can have up to 32 causes and the interrupt model supports + * masking/unmasking each cause independently + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 mask) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_set_irq_mask *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_MASK, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_set_irq_mask *)cmd.params; + cmd_params->mask = cpu_to_le32(mask); + cmd_params->irq_index = irq_index; + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_get_irq_status() - Get the current status of any pending interrupts + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @irq_index: The interrupt index to configure + * @status: Returned interrupts status - one bit per cause: + * 0 = no interrupt pending + * 1 = interrupt pending + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_get_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 *status) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_get_irq_status *cmd_params; + struct dpsw_rsp_get_irq_status *rsp_params; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_IRQ_STATUS, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_get_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(*status); + cmd_params->irq_index = irq_index; + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + rsp_params = (struct dpsw_rsp_get_irq_status *)cmd.params; + *status = le32_to_cpu(rsp_params->status); + + return 0; +} + +/** + * dpsw_clear_irq_status() - Clear a pending interrupt's status + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPCI object + * @irq_index: The interrupt index to configure + * @status: bits to clear (W1C) - one bit per cause: + * 0 = don't change + * 1 = clear status bit + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 status) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_clear_irq_status *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLEAR_IRQ_STATUS, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_clear_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(status); + cmd_params->irq_index = irq_index; + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_get_attributes() - Retrieve DPSW attributes + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @attr: Returned DPSW attributes + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpsw_attr *attr) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_rsp_get_attr *rsp_params; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_ATTR, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + rsp_params = (struct dpsw_rsp_get_attr *)cmd.params; + attr->num_ifs = le16_to_cpu(rsp_params->num_ifs); + attr->max_fdbs = rsp_params->max_fdbs; + attr->num_fdbs = rsp_params->num_fdbs; + attr->max_vlans = le16_to_cpu(rsp_params->max_vlans); + attr->num_vlans = le16_to_cpu(rsp_params->num_vlans); + attr->max_fdb_entries = le16_to_cpu(rsp_params->max_fdb_entries); + attr->fdb_aging_time = le16_to_cpu(rsp_params->fdb_aging_time); + attr->id = le32_to_cpu(rsp_params->dpsw_id); + attr->mem_size = le16_to_cpu(rsp_params->mem_size); + attr->max_fdb_mc_groups = le16_to_cpu(rsp_params->max_fdb_mc_groups); + attr->max_meters_per_if = rsp_params->max_meters_per_if; + attr->options = le64_to_cpu(rsp_params->options); + attr->component_type = dpsw_get_field(rsp_params->component_type, + COMPONENT_TYPE); + + return 0; +} + +/** + * dpsw_if_set_link_cfg() - Set the link configuration. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface id + * @cfg: Link configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + struct dpsw_link_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_set_link_cfg *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LINK_CFG, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_set_link_cfg *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + cmd_params->rate = cpu_to_le32(cfg->rate); + cmd_params->options = cpu_to_le64(cfg->options); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_if_get_link_state - Return the link state + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface id + * @state: Link state 1 - linkup, 0 - link down or disconnected + * + * @Return '0' on Success; Error code otherwise. + */ +int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + struct dpsw_link_state *state) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_get_link_state *cmd_params; + struct dpsw_rsp_if_get_link_state *rsp_params; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_LINK_STATE, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_get_link_state *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + rsp_params = (struct dpsw_rsp_if_get_link_state *)cmd.params; + state->rate = le32_to_cpu(rsp_params->rate); + state->options = le64_to_cpu(rsp_params->options); + state->up = dpsw_get_field(rsp_params->up, UP); + + return 0; +} + +/** + * dpsw_if_set_flooding() - Enable Disable flooding for particular interface + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * @en: 1 - enable, 0 - disable + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_set_flooding(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + u8 en) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_set_flooding *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_FLOODING, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_set_flooding *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + dpsw_set_field(cmd_params->enable, ENABLE, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_if_set_broadcast() - Enable/disable broadcast for particular interface + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * @en: 1 - enable, 0 - disable + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + u8 en) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_set_broadcast *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_BROADCAST, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_set_broadcast *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + dpsw_set_field(cmd_params->enable, ENABLE, en); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_if_set_tci() - Set default VLAN Tag Control Information (TCI) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * @cfg: Tag Control Information Configuration + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_set_tci(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + const struct dpsw_tci_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_set_tci *cmd_params; + u16 tmp_conf = 0; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_TCI, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_set_tci *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + dpsw_set_field(tmp_conf, VLAN_ID, cfg->vlan_id); + dpsw_set_field(tmp_conf, DEI, cfg->dei); + dpsw_set_field(tmp_conf, PCP, cfg->pcp); + cmd_params->conf = cpu_to_le16(tmp_conf); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * @cfg: STP State configuration parameters + * + * The following STP states are supported - + * blocking, listening, learning, forwarding and disabled. + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_set_stp(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + const struct dpsw_stp_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_set_stp *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_STP, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_set_stp *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id); + dpsw_set_field(cmd_params->state, STATE, cfg->state); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_if_get_counter() - Get specific counter of particular interface + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * @type: Counter type + * @counter: return value + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_get_counter(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + enum dpsw_counter type, + u64 *counter) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_get_counter *cmd_params; + struct dpsw_rsp_if_get_counter *rsp_params; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_COUNTER, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_get_counter *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + dpsw_set_field(cmd_params->type, COUNTER_TYPE, type); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + rsp_params = (struct dpsw_rsp_if_get_counter *)cmd.params; + *counter = le64_to_cpu(rsp_params->counter); + + return 0; +} + +/** + * dpsw_if_enable() - Enable Interface + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_ENABLE, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_if_disable() - Disable Interface + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_DISABLE, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_if_set_max_frame_length() - Set Maximum Receive frame length. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * @frame_length: Maximum Frame Length + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + u16 frame_length) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_set_max_frame_length *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_set_max_frame_length *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + cmd_params->frame_length = cpu_to_le16(frame_length); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_vlan_add() - Adding new VLAN to DPSW. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @vlan_id: VLAN Identifier + * @cfg: VLAN configuration + * + * Only VLAN ID and FDB ID are required parameters here. + * 12 bit VLAN ID is defined in IEEE802.1Q. + * Adding a duplicate VLAN ID is not allowed. + * FDB ID can be shared across multiple VLANs. Shared learning + * is obtained by calling dpsw_vlan_add for multiple VLAN IDs + * with same fdb_id + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_vlan_add(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_vlan_add *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD, + cmd_flags, + token); + cmd_params = (struct dpsw_vlan_add *)cmd.params; + cmd_params->fdb_id = cpu_to_le16(cfg->fdb_id); + cmd_params->vlan_id = cpu_to_le16(vlan_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_vlan_add_if() - Adding a set of interfaces to an existing VLAN. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @vlan_id: VLAN Identifier + * @cfg: Set of interfaces to add + * + * It adds only interfaces not belonging to this VLAN yet, + * otherwise an error is generated and an entire command is + * ignored. This function can be called numerous times always + * providing required interfaces delta. + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_vlan_manage_if *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; + cmd_params->vlan_id = cpu_to_le16(vlan_id); + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_vlan_add_if_untagged() - Defining a set of interfaces that should be + * transmitted as untagged. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @vlan_id: VLAN Identifier + * @cfg: Set of interfaces that should be transmitted as untagged + * + * These interfaces should already belong to this VLAN. + * By default all interfaces are transmitted as tagged. + * Providing un-existing interface or untagged interface that is + * configured untagged already generates an error and the entire + * command is ignored. + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_vlan_manage_if *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF_UNTAGGED, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; + cmd_params->vlan_id = cpu_to_le16(vlan_id); + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_vlan_remove_if() - Remove interfaces from an existing VLAN. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @vlan_id: VLAN Identifier + * @cfg: Set of interfaces that should be removed + * + * Interfaces must belong to this VLAN, otherwise an error + * is returned and an the command is ignored + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_vlan_manage_if *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; + cmd_params->vlan_id = cpu_to_le16(vlan_id); + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_vlan_remove_if_untagged() - Define a set of interfaces that should be + * converted from transmitted as untagged to transmit as tagged. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @vlan_id: VLAN Identifier + * @cfg: Set of interfaces that should be removed + * + * Interfaces provided by API have to belong to this VLAN and + * configured untagged, otherwise an error is returned and the + * command is ignored + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_vlan_manage_if *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; + cmd_params->vlan_id = cpu_to_le16(vlan_id); + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_vlan_remove() - Remove an entire VLAN + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @vlan_id: VLAN Identifier + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_vlan_remove(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_vlan_remove *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_vlan_remove *)cmd.params; + cmd_params->vlan_id = cpu_to_le16(vlan_id); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_fdb_add_unicast() - Function adds an unicast entry into MAC lookup table + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @fdb_id: Forwarding Database Identifier + * @cfg: Unicast entry configuration + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_unicast_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_fdb_unicast_op *cmd_params; + int i; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_UNICAST, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params; + cmd_params->fdb_id = cpu_to_le16(fdb_id); + cmd_params->if_egress = cpu_to_le16(cfg->if_egress); + for (i = 0; i < 6; i++) + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_fdb_remove_unicast() - removes an entry from MAC lookup table + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @fdb_id: Forwarding Database Identifier + * @cfg: Unicast entry configuration + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_unicast_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_fdb_unicast_op *cmd_params; + int i; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_UNICAST, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_fdb_unicast_op *)cmd.params; + cmd_params->fdb_id = cpu_to_le16(fdb_id); + for (i = 0; i < 6; i++) + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; + cmd_params->if_egress = cpu_to_le16(cfg->if_egress); + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_fdb_add_multicast() - Add a set of egress interfaces to multi-cast group + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @fdb_id: Forwarding Database Identifier + * @cfg: Multicast entry configuration + * + * If group doesn't exist, it will be created. + * It adds only interfaces not belonging to this multicast group + * yet, otherwise error will be generated and the command is + * ignored. + * This function may be called numerous times always providing + * required interfaces delta. + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_multicast_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_fdb_multicast_op *cmd_params; + int i; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_MULTICAST, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params; + cmd_params->fdb_id = cpu_to_le16(fdb_id); + cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); + for (i = 0; i < 6; i++) + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_fdb_remove_multicast() - Removing interfaces from an existing multicast + * group. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @fdb_id: Forwarding Database Identifier + * @cfg: Multicast entry configuration + * + * Interfaces provided by this API have to exist in the group, + * otherwise an error will be returned and an entire command + * ignored. If there is no interface left in the group, + * an entire group is deleted + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_multicast_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_fdb_multicast_op *cmd_params; + int i; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_MULTICAST, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_fdb_multicast_op *)cmd.params; + cmd_params->fdb_id = cpu_to_le16(fdb_id); + cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); + dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); + build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); + for (i = 0; i < 6; i++) + cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_fdb_set_learning_mode() - Define FDB learning mode + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @fdb_id: Forwarding Database Identifier + * @mode: Learning mode + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + enum dpsw_fdb_learning_mode mode) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_fdb_set_learning_mode *cmd_params; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_SET_LEARNING_MODE, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_fdb_set_learning_mode *)cmd.params; + cmd_params->fdb_id = cpu_to_le16(fdb_id); + dpsw_set_field(cmd_params->mode, LEARNING_MODE, mode); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpsw_get_api_version() - Get Data Path Switch API version + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of data path switch API + * @minor_ver: Minor version of data path switch API + * + * Return: '0' on Success; Error code otherwise. + */ +int dpsw_get_api_version(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 *major_ver, + u16 *minor_ver) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_rsp_get_api_version *rsp_params; + int err; + + cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_API_VERSION, + cmd_flags, + 0); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dpsw_rsp_get_api_version *)cmd.params; + *major_ver = le16_to_cpu(rsp_params->version_major); + *minor_ver = le16_to_cpu(rsp_params->version_minor); + + return 0; +} diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h new file mode 100644 index 000000000000..3335adde0193 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h @@ -0,0 +1,586 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + * + */ + +#ifndef __FSL_DPSW_H +#define __FSL_DPSW_H + +/* Data Path L2-Switch API + * Contains API for handling DPSW topology and functionality + */ + +struct fsl_mc_io; + +/** + * DPSW general definitions + */ + +/** + * Maximum number of traffic class priorities + */ +#define DPSW_MAX_PRIORITIES 8 +/** + * Maximum number of interfaces + */ +#define DPSW_MAX_IF 64 + +int dpsw_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dpsw_id, + u16 *token); + +int dpsw_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +/** + * DPSW options + */ + +/** + * Disable flooding + */ +#define DPSW_OPT_FLOODING_DIS 0x0000000000000001ULL +/** + * Disable Multicast + */ +#define DPSW_OPT_MULTICAST_DIS 0x0000000000000004ULL +/** + * Support control interface + */ +#define DPSW_OPT_CTRL_IF_DIS 0x0000000000000010ULL +/** + * Disable flooding metering + */ +#define DPSW_OPT_FLOODING_METERING_DIS 0x0000000000000020ULL +/** + * Enable metering + */ +#define DPSW_OPT_METERING_EN 0x0000000000000040ULL + +/** + * enum dpsw_component_type - component type of a bridge + * @DPSW_COMPONENT_TYPE_C_VLAN: A C-VLAN component of an + * enterprise VLAN bridge or of a Provider Bridge used + * to process C-tagged frames + * @DPSW_COMPONENT_TYPE_S_VLAN: An S-VLAN component of a + * Provider Bridge + * + */ +enum dpsw_component_type { + DPSW_COMPONENT_TYPE_C_VLAN = 0, + DPSW_COMPONENT_TYPE_S_VLAN +}; + +/** + * struct dpsw_cfg - DPSW configuration + * @num_ifs: Number of external and internal interfaces + * @adv: Advanced parameters; default is all zeros; + * use this structure to change default settings + */ +struct dpsw_cfg { + u16 num_ifs; + /** + * struct adv - Advanced parameters + * @options: Enable/Disable DPSW features (bitmap) + * @max_vlans: Maximum Number of VLAN's; 0 - indicates default 16 + * @max_meters_per_if: Number of meters per interface + * @max_fdbs: Maximum Number of FDB's; 0 - indicates default 16 + * @max_fdb_entries: Number of FDB entries for default FDB table; + * 0 - indicates default 1024 entries. + * @fdb_aging_time: Default FDB aging time for default FDB table; + * 0 - indicates default 300 seconds + * @max_fdb_mc_groups: Number of multicast groups in each FDB table; + * 0 - indicates default 32 + * @component_type: Indicates the component type of this bridge + */ + struct { + u64 options; + u16 max_vlans; + u8 max_meters_per_if; + u8 max_fdbs; + u16 max_fdb_entries; + u16 fdb_aging_time; + u16 max_fdb_mc_groups; + enum dpsw_component_type component_type; + } adv; +}; + +int dpsw_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpsw_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpsw_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +/** + * DPSW IRQ Index and Events + */ + +#define DPSW_IRQ_INDEX_IF 0x0000 +#define DPSW_IRQ_INDEX_L2SW 0x0001 + +/** + * IRQ event - Indicates that the link state changed + */ +#define DPSW_IRQ_EVENT_LINK_CHANGED 0x0001 + +/** + * struct dpsw_irq_cfg - IRQ configuration + * @addr: Address that must be written to signal a message-based interrupt + * @val: Value to write into irq_addr address + * @irq_num: A user defined number associated with this IRQ + */ +struct dpsw_irq_cfg { + u64 addr; + u32 val; + int irq_num; +}; + +int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u8 en); + +int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 mask); + +int dpsw_get_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 *status); + +int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 status); + +/** + * struct dpsw_attr - Structure representing DPSW attributes + * @id: DPSW object ID + * @options: Enable/Disable DPSW features + * @max_vlans: Maximum Number of VLANs + * @max_meters_per_if: Number of meters per interface + * @max_fdbs: Maximum Number of FDBs + * @max_fdb_entries: Number of FDB entries for default FDB table; + * 0 - indicates default 1024 entries. + * @fdb_aging_time: Default FDB aging time for default FDB table; + * 0 - indicates default 300 seconds + * @max_fdb_mc_groups: Number of multicast groups in each FDB table; + * 0 - indicates default 32 + * @mem_size: DPSW frame storage memory size + * @num_ifs: Number of interfaces + * @num_vlans: Current number of VLANs + * @num_fdbs: Current number of FDBs + * @component_type: Component type of this bridge + */ +struct dpsw_attr { + int id; + u64 options; + u16 max_vlans; + u8 max_meters_per_if; + u8 max_fdbs; + u16 max_fdb_entries; + u16 fdb_aging_time; + u16 max_fdb_mc_groups; + u16 num_ifs; + u16 mem_size; + u16 num_vlans; + u8 num_fdbs; + enum dpsw_component_type component_type; +}; + +int dpsw_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpsw_attr *attr); + +/** + * enum dpsw_action - Action selection for special/control frames + * @DPSW_ACTION_DROP: Drop frame + * @DPSW_ACTION_REDIRECT: Redirect frame to control port + */ +enum dpsw_action { + DPSW_ACTION_DROP = 0, + DPSW_ACTION_REDIRECT = 1 +}; + +/** + * Enable auto-negotiation + */ +#define DPSW_LINK_OPT_AUTONEG 0x0000000000000001ULL +/** + * Enable half-duplex mode + */ +#define DPSW_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL +/** + * Enable pause frames + */ +#define DPSW_LINK_OPT_PAUSE 0x0000000000000004ULL +/** + * Enable a-symmetric pause frames + */ +#define DPSW_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL + +/** + * struct dpsw_link_cfg - Structure representing DPSW link configuration + * @rate: Rate + * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values + */ +struct dpsw_link_cfg { + u32 rate; + u64 options; +}; + +int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + struct dpsw_link_cfg *cfg); +/** + * struct dpsw_link_state - Structure representing DPSW link state + * @rate: Rate + * @options: Mask of available options; use 'DPSW_LINK_OPT_<X>' values + * @up: 0 - covers two cases: down and disconnected, 1 - up + */ +struct dpsw_link_state { + u32 rate; + u64 options; + u8 up; +}; + +int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + struct dpsw_link_state *state); + +int dpsw_if_set_flooding(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + u8 en); + +int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + u8 en); + +/** + * struct dpsw_tci_cfg - Tag Control Information (TCI) configuration + * @pcp: Priority Code Point (PCP): a 3-bit field which refers + * to the IEEE 802.1p priority + * @dei: Drop Eligible Indicator (DEI): a 1-bit field. May be used + * separately or in conjunction with PCP to indicate frames + * eligible to be dropped in the presence of congestion + * @vlan_id: VLAN Identifier (VID): a 12-bit field specifying the VLAN + * to which the frame belongs. The hexadecimal values + * of 0x000 and 0xFFF are reserved; + * all other values may be used as VLAN identifiers, + * allowing up to 4,094 VLANs + */ +struct dpsw_tci_cfg { + u8 pcp; + u8 dei; + u16 vlan_id; +}; + +int dpsw_if_set_tci(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + const struct dpsw_tci_cfg *cfg); + +/** + * enum dpsw_stp_state - Spanning Tree Protocol (STP) states + * @DPSW_STP_STATE_BLOCKING: Blocking state + * @DPSW_STP_STATE_LISTENING: Listening state + * @DPSW_STP_STATE_LEARNING: Learning state + * @DPSW_STP_STATE_FORWARDING: Forwarding state + * + */ +enum dpsw_stp_state { + DPSW_STP_STATE_DISABLED = 0, + DPSW_STP_STATE_LISTENING = 1, + DPSW_STP_STATE_LEARNING = 2, + DPSW_STP_STATE_FORWARDING = 3, + DPSW_STP_STATE_BLOCKING = 0 +}; + +/** + * struct dpsw_stp_cfg - Spanning Tree Protocol (STP) Configuration + * @vlan_id: VLAN ID STP state + * @state: STP state + */ +struct dpsw_stp_cfg { + u16 vlan_id; + enum dpsw_stp_state state; +}; + +int dpsw_if_set_stp(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + const struct dpsw_stp_cfg *cfg); + +/** + * enum dpsw_accepted_frames - Types of frames to accept + * @DPSW_ADMIT_ALL: The device accepts VLAN tagged, untagged and + * priority tagged frames + * @DPSW_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or + * Priority-Tagged frames received on this interface. + * + */ +enum dpsw_accepted_frames { + DPSW_ADMIT_ALL = 1, + DPSW_ADMIT_ONLY_VLAN_TAGGED = 3 +}; + +/** + * enum dpsw_counter - Counters types + * @DPSW_CNT_ING_FRAME: Counts ingress frames + * @DPSW_CNT_ING_BYTE: Counts ingress bytes + * @DPSW_CNT_ING_FLTR_FRAME: Counts filtered ingress frames + * @DPSW_CNT_ING_FRAME_DISCARD: Counts discarded ingress frame + * @DPSW_CNT_ING_MCAST_FRAME: Counts ingress multicast frames + * @DPSW_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes + * @DPSW_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames + * @DPSW_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes + * @DPSW_CNT_EGR_FRAME: Counts egress frames + * @DPSW_CNT_EGR_BYTE: Counts eEgress bytes + * @DPSW_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames + * @DPSW_CNT_EGR_STP_FRAME_DISCARD: Counts egress STP discarded frames + */ +enum dpsw_counter { + DPSW_CNT_ING_FRAME = 0x0, + DPSW_CNT_ING_BYTE = 0x1, + DPSW_CNT_ING_FLTR_FRAME = 0x2, + DPSW_CNT_ING_FRAME_DISCARD = 0x3, + DPSW_CNT_ING_MCAST_FRAME = 0x4, + DPSW_CNT_ING_MCAST_BYTE = 0x5, + DPSW_CNT_ING_BCAST_FRAME = 0x6, + DPSW_CNT_ING_BCAST_BYTES = 0x7, + DPSW_CNT_EGR_FRAME = 0x8, + DPSW_CNT_EGR_BYTE = 0x9, + DPSW_CNT_EGR_FRAME_DISCARD = 0xa, + DPSW_CNT_EGR_STP_FRAME_DISCARD = 0xb +}; + +int dpsw_if_get_counter(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + enum dpsw_counter type, + u64 *counter); + +int dpsw_if_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id); + +int dpsw_if_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id); + +int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + u16 frame_length); + +/** + * struct dpsw_vlan_cfg - VLAN Configuration + * @fdb_id: Forwarding Data Base + */ +struct dpsw_vlan_cfg { + u16 fdb_id; +}; + +int dpsw_vlan_add(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_cfg *cfg); + +/** + * struct dpsw_vlan_if_cfg - Set of VLAN Interfaces + * @num_ifs: The number of interfaces that are assigned to the egress + * list for this VLAN + * @if_id: The set of interfaces that are + * assigned to the egress list for this VLAN + */ +struct dpsw_vlan_if_cfg { + u16 num_ifs; + u16 if_id[DPSW_MAX_IF]; +}; + +int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg); + +int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg); + +int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg); + +int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id, + const struct dpsw_vlan_if_cfg *cfg); + +int dpsw_vlan_remove(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 vlan_id); + +/** + * enum dpsw_fdb_entry_type - FDB Entry type - Static/Dynamic + * @DPSW_FDB_ENTRY_STATIC: Static entry + * @DPSW_FDB_ENTRY_DINAMIC: Dynamic entry + */ +enum dpsw_fdb_entry_type { + DPSW_FDB_ENTRY_STATIC = 0, + DPSW_FDB_ENTRY_DINAMIC = 1 +}; + +/** + * struct dpsw_fdb_unicast_cfg - Unicast entry configuration + * @type: Select static or dynamic entry + * @mac_addr: MAC address + * @if_egress: Egress interface ID + */ +struct dpsw_fdb_unicast_cfg { + enum dpsw_fdb_entry_type type; + u8 mac_addr[6]; + u16 if_egress; +}; + +int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_unicast_cfg *cfg); + +int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_unicast_cfg *cfg); + +/** + * struct dpsw_fdb_multicast_cfg - Multi-cast entry configuration + * @type: Select static or dynamic entry + * @mac_addr: MAC address + * @num_ifs: Number of external and internal interfaces + * @if_id: Egress interface IDs + */ +struct dpsw_fdb_multicast_cfg { + enum dpsw_fdb_entry_type type; + u8 mac_addr[6]; + u16 num_ifs; + u16 if_id[DPSW_MAX_IF]; +}; + +int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_multicast_cfg *cfg); + +int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + const struct dpsw_fdb_multicast_cfg *cfg); + +/** + * enum dpsw_fdb_learning_mode - Auto-learning modes + * @DPSW_FDB_LEARNING_MODE_DIS: Disable Auto-learning + * @DPSW_FDB_LEARNING_MODE_HW: Enable HW auto-Learning + * @DPSW_FDB_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU + * @DPSW_FDB_LEARNING_MODE_SECURE: Enable secure learning by CPU + * + * NONE - SECURE LEARNING + * SMAC found DMAC found CTLU Action + * v v Forward frame to + * 1. DMAC destination + * - v Forward frame to + * 1. DMAC destination + * 2. Control interface + * v - Forward frame to + * 1. Flooding list of interfaces + * - - Forward frame to + * 1. Flooding list of interfaces + * 2. Control interface + * SECURE LEARING + * SMAC found DMAC found CTLU Action + * v v Forward frame to + * 1. DMAC destination + * - v Forward frame to + * 1. Control interface + * v - Forward frame to + * 1. Flooding list of interfaces + * - - Forward frame to + * 1. Control interface + */ +enum dpsw_fdb_learning_mode { + DPSW_FDB_LEARNING_MODE_DIS = 0, + DPSW_FDB_LEARNING_MODE_HW = 1, + DPSW_FDB_LEARNING_MODE_NON_SECURE = 2, + DPSW_FDB_LEARNING_MODE_SECURE = 3 +}; + +int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 fdb_id, + enum dpsw_fdb_learning_mode mode); + +/** + * struct dpsw_fdb_attr - FDB Attributes + * @max_fdb_entries: Number of FDB entries + * @fdb_aging_time: Aging time in seconds + * @learning_mode: Learning mode + * @num_fdb_mc_groups: Current number of multicast groups + * @max_fdb_mc_groups: Maximum number of multicast groups + */ +struct dpsw_fdb_attr { + u16 max_fdb_entries; + u16 fdb_aging_time; + enum dpsw_fdb_learning_mode learning_mode; + u16 num_fdb_mc_groups; + u16 max_fdb_mc_groups; +}; + +int dpsw_get_api_version(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 *major_ver, + u16 *minor_ver); + +#endif /* __FSL_DPSW_H */ diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c new file mode 100644 index 000000000000..926a0c053e18 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw-ethtool.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DPAA2 Ethernet Switch ethtool support + * + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + * + */ + +#include "ethsw.h" + +static struct { + enum dpsw_counter id; + char name[ETH_GSTRING_LEN]; +} ethsw_ethtool_counters[] = { + {DPSW_CNT_ING_FRAME, "rx frames"}, + {DPSW_CNT_ING_BYTE, "rx bytes"}, + {DPSW_CNT_ING_FLTR_FRAME, "rx filtered frames"}, + {DPSW_CNT_ING_FRAME_DISCARD, "rx discarded frames"}, + {DPSW_CNT_ING_BCAST_FRAME, "rx b-cast frames"}, + {DPSW_CNT_ING_BCAST_BYTES, "rx b-cast bytes"}, + {DPSW_CNT_ING_MCAST_FRAME, "rx m-cast frames"}, + {DPSW_CNT_ING_MCAST_BYTE, "rx m-cast bytes"}, + {DPSW_CNT_EGR_FRAME, "tx frames"}, + {DPSW_CNT_EGR_BYTE, "tx bytes"}, + {DPSW_CNT_EGR_FRAME_DISCARD, "tx discarded frames"}, + +}; + +#define ETHSW_NUM_COUNTERS ARRAY_SIZE(ethsw_ethtool_counters) + +static void ethsw_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + u16 version_major, version_minor; + int err; + + strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); + + err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0, + &version_major, + &version_minor); + if (err) + strlcpy(drvinfo->fw_version, "N/A", + sizeof(drvinfo->fw_version)); + else + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), + "%u.%u", version_major, version_minor); + + strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent), + sizeof(drvinfo->bus_info)); +} + +static int +ethsw_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *link_ksettings) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + struct dpsw_link_state state = {0}; + int err = 0; + + err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + &state); + if (err) { + netdev_err(netdev, "ERROR %d getting link state", err); + goto out; + } + + /* At the moment, we have no way of interrogating the DPMAC + * from the DPSW side or there may not exist a DPMAC at all. + * Report only autoneg state, duplexity and speed. + */ + if (state.options & DPSW_LINK_OPT_AUTONEG) + link_ksettings->base.autoneg = AUTONEG_ENABLE; + if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX)) + link_ksettings->base.duplex = DUPLEX_FULL; + link_ksettings->base.speed = state.rate; + +out: + return err; +} + +static int +ethsw_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *link_ksettings) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + struct dpsw_link_cfg cfg = {0}; + int err = 0; + + netdev_dbg(netdev, "Setting link parameters..."); + + /* Due to a temporary MC limitation, the DPSW port must be down + * in order to be able to change link settings. Taking steps to let + * the user know that. + */ + if (netif_running(netdev)) { + netdev_info(netdev, "Sorry, interface must be brought down first.\n"); + return -EACCES; + } + + cfg.rate = link_ksettings->base.speed; + if (link_ksettings->base.autoneg == AUTONEG_ENABLE) + cfg.options |= DPSW_LINK_OPT_AUTONEG; + else + cfg.options &= ~DPSW_LINK_OPT_AUTONEG; + if (link_ksettings->base.duplex == DUPLEX_HALF) + cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX; + else + cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX; + + err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + &cfg); + if (err) + /* ethtool will be loud enough if we return an error; no point + * in putting our own error message on the console by default + */ + netdev_dbg(netdev, "ERROR %d setting link cfg", err); + + return err; +} + +static int ethsw_ethtool_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ETHSW_NUM_COUNTERS; + default: + return -EOPNOTSUPP; + } +} + +static void ethsw_ethtool_get_strings(struct net_device *netdev, + u32 stringset, u8 *data) +{ + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ETHSW_NUM_COUNTERS; i++) + memcpy(data + i * ETH_GSTRING_LEN, + ethsw_ethtool_counters[i].name, ETH_GSTRING_LEN); + break; + } +} + +static void ethsw_ethtool_get_stats(struct net_device *netdev, + struct ethtool_stats *stats, + u64 *data) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int i, err; + + memset(data, 0, + sizeof(u64) * ETHSW_NUM_COUNTERS); + + for (i = 0; i < ETHSW_NUM_COUNTERS; i++) { + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + ethsw_ethtool_counters[i].id, + &data[i]); + if (err) + netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n", + ethsw_ethtool_counters[i].name, err); + } +} + +const struct ethtool_ops ethsw_port_ethtool_ops = { + .get_drvinfo = ethsw_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_link_ksettings = ethsw_get_link_ksettings, + .set_link_ksettings = ethsw_set_link_ksettings, + .get_strings = ethsw_ethtool_get_strings, + .get_ethtool_stats = ethsw_ethtool_get_stats, + .get_sset_count = ethsw_ethtool_get_sset_count, +}; diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c new file mode 100644 index 000000000000..c723a04bc3d6 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c @@ -0,0 +1,1508 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DPAA2 Ethernet Switch driver + * + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + * + */ + +#include <linux/module.h> + +#include <linux/interrupt.h> +#include <linux/msi.h> +#include <linux/kthread.h> +#include <linux/workqueue.h> + +#include <linux/fsl/mc.h> + +#include "ethsw.h" + +static struct workqueue_struct *ethsw_owq; + +/* Minimal supported DPSW version */ +#define DPSW_MIN_VER_MAJOR 8 +#define DPSW_MIN_VER_MINOR 0 + +#define DEFAULT_VLAN_ID 1 + +static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid) +{ + int err; + + struct dpsw_vlan_cfg vcfg = { + .fdb_id = 0, + }; + + if (ethsw->vlans[vid]) { + dev_err(ethsw->dev, "VLAN already configured\n"); + return -EEXIST; + } + + err = dpsw_vlan_add(ethsw->mc_io, 0, + ethsw->dpsw_handle, vid, &vcfg); + if (err) { + dev_err(ethsw->dev, "dpsw_vlan_add err %d\n", err); + return err; + } + ethsw->vlans[vid] = ETHSW_VLAN_MEMBER; + + return 0; +} + +static int ethsw_port_set_tci(struct ethsw_port_priv *port_priv, + struct dpsw_tci_cfg *tci_cfg) +{ + struct ethsw_core *ethsw = port_priv->ethsw_data; + struct net_device *netdev = port_priv->netdev; + bool is_oper; + int err, ret; + + /* Interface needs to be down to change PVID */ + is_oper = netif_oper_up(netdev); + if (is_oper) { + err = dpsw_if_disable(ethsw->mc_io, 0, + ethsw->dpsw_handle, + port_priv->idx); + if (err) { + netdev_err(netdev, "dpsw_if_disable err %d\n", err); + return err; + } + } + + err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, + port_priv->idx, tci_cfg); + if (err) { + netdev_err(netdev, "dpsw_if_set_tci err %d\n", err); + goto set_tci_error; + } + + /* Delete previous PVID info and mark the new one */ + if (port_priv->pvid) + port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID; + port_priv->vlans[tci_cfg->vlan_id] |= ETHSW_VLAN_PVID; + port_priv->pvid = tci_cfg->vlan_id; + +set_tci_error: + if (is_oper) { + ret = dpsw_if_enable(ethsw->mc_io, 0, + ethsw->dpsw_handle, + port_priv->idx); + if (ret) { + netdev_err(netdev, "dpsw_if_enable err %d\n", ret); + return ret; + } + } + + return err; +} + +static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv, + u16 vid, u16 flags) +{ + struct ethsw_core *ethsw = port_priv->ethsw_data; + struct net_device *netdev = port_priv->netdev; + struct dpsw_vlan_if_cfg vcfg; + int err; + + if (port_priv->vlans[vid]) { + netdev_warn(netdev, "VLAN %d already configured\n", vid); + return -EEXIST; + } + + vcfg.num_ifs = 1; + vcfg.if_id[0] = port_priv->idx; + err = dpsw_vlan_add_if(ethsw->mc_io, 0, ethsw->dpsw_handle, vid, &vcfg); + if (err) { + netdev_err(netdev, "dpsw_vlan_add_if err %d\n", err); + return err; + } + + port_priv->vlans[vid] = ETHSW_VLAN_MEMBER; + + if (flags & BRIDGE_VLAN_INFO_UNTAGGED) { + err = dpsw_vlan_add_if_untagged(ethsw->mc_io, 0, + ethsw->dpsw_handle, + vid, &vcfg); + if (err) { + netdev_err(netdev, + "dpsw_vlan_add_if_untagged err %d\n", err); + return err; + } + port_priv->vlans[vid] |= ETHSW_VLAN_UNTAGGED; + } + + if (flags & BRIDGE_VLAN_INFO_PVID) { + struct dpsw_tci_cfg tci_cfg = { + .pcp = 0, + .dei = 0, + .vlan_id = vid, + }; + + err = ethsw_port_set_tci(port_priv, &tci_cfg); + if (err) + return err; + } + + return 0; +} + +static int ethsw_set_learning(struct ethsw_core *ethsw, u8 flag) +{ + enum dpsw_fdb_learning_mode learn_mode; + int err; + + if (flag) + learn_mode = DPSW_FDB_LEARNING_MODE_HW; + else + learn_mode = DPSW_FDB_LEARNING_MODE_DIS; + + err = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0, + learn_mode); + if (err) { + dev_err(ethsw->dev, "dpsw_fdb_set_learning_mode err %d\n", err); + return err; + } + ethsw->learning = !!flag; + + return 0; +} + +static int ethsw_port_set_flood(struct ethsw_port_priv *port_priv, u8 flag) +{ + int err; + + err = dpsw_if_set_flooding(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, flag); + if (err) { + netdev_err(port_priv->netdev, + "dpsw_fdb_set_learning_mode err %d\n", err); + return err; + } + port_priv->flood = !!flag; + + return 0; +} + +static int ethsw_port_set_stp_state(struct ethsw_port_priv *port_priv, u8 state) +{ + struct dpsw_stp_cfg stp_cfg = { + .vlan_id = DEFAULT_VLAN_ID, + .state = state, + }; + int err; + + if (!netif_oper_up(port_priv->netdev) || state == port_priv->stp_state) + return 0; /* Nothing to do */ + + err = dpsw_if_set_stp(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, &stp_cfg); + if (err) { + netdev_err(port_priv->netdev, + "dpsw_if_set_stp err %d\n", err); + return err; + } + + port_priv->stp_state = state; + + return 0; +} + +static int ethsw_dellink_switch(struct ethsw_core *ethsw, u16 vid) +{ + struct ethsw_port_priv *ppriv_local = NULL; + int i, err; + + if (!ethsw->vlans[vid]) + return -ENOENT; + + err = dpsw_vlan_remove(ethsw->mc_io, 0, ethsw->dpsw_handle, vid); + if (err) { + dev_err(ethsw->dev, "dpsw_vlan_remove err %d\n", err); + return err; + } + ethsw->vlans[vid] = 0; + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + ppriv_local = ethsw->ports[i]; + ppriv_local->vlans[vid] = 0; + } + + return 0; +} + +static int ethsw_port_fdb_add_uc(struct ethsw_port_priv *port_priv, + const unsigned char *addr) +{ + struct dpsw_fdb_unicast_cfg entry = {0}; + int err; + + entry.if_egress = port_priv->idx; + entry.type = DPSW_FDB_ENTRY_STATIC; + ether_addr_copy(entry.mac_addr, addr); + + err = dpsw_fdb_add_unicast(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + 0, &entry); + if (err) + netdev_err(port_priv->netdev, + "dpsw_fdb_add_unicast err %d\n", err); + return err; +} + +static int ethsw_port_fdb_del_uc(struct ethsw_port_priv *port_priv, + const unsigned char *addr) +{ + struct dpsw_fdb_unicast_cfg entry = {0}; + int err; + + entry.if_egress = port_priv->idx; + entry.type = DPSW_FDB_ENTRY_STATIC; + ether_addr_copy(entry.mac_addr, addr); + + err = dpsw_fdb_remove_unicast(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + 0, &entry); + /* Silently discard error for calling multiple times the del command */ + if (err && err != -ENXIO) + netdev_err(port_priv->netdev, + "dpsw_fdb_remove_unicast err %d\n", err); + return err; +} + +static int ethsw_port_fdb_add_mc(struct ethsw_port_priv *port_priv, + const unsigned char *addr) +{ + struct dpsw_fdb_multicast_cfg entry = {0}; + int err; + + ether_addr_copy(entry.mac_addr, addr); + entry.type = DPSW_FDB_ENTRY_STATIC; + entry.num_ifs = 1; + entry.if_id[0] = port_priv->idx; + + err = dpsw_fdb_add_multicast(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + 0, &entry); + /* Silently discard error for calling multiple times the add command */ + if (err && err != -ENXIO) + netdev_err(port_priv->netdev, "dpsw_fdb_add_multicast err %d\n", + err); + return err; +} + +static int ethsw_port_fdb_del_mc(struct ethsw_port_priv *port_priv, + const unsigned char *addr) +{ + struct dpsw_fdb_multicast_cfg entry = {0}; + int err; + + ether_addr_copy(entry.mac_addr, addr); + entry.type = DPSW_FDB_ENTRY_STATIC; + entry.num_ifs = 1; + entry.if_id[0] = port_priv->idx; + + err = dpsw_fdb_remove_multicast(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + 0, &entry); + /* Silently discard error for calling multiple times the del command */ + if (err && err != -ENAVAIL) + netdev_err(port_priv->netdev, + "dpsw_fdb_remove_multicast err %d\n", err); + return err; +} + +static void port_get_stats(struct net_device *netdev, + struct rtnl_link_stats64 *stats) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + u64 tmp; + int err; + + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + DPSW_CNT_ING_FRAME, &stats->rx_packets); + if (err) + goto error; + + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + DPSW_CNT_EGR_FRAME, &stats->tx_packets); + if (err) + goto error; + + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + DPSW_CNT_ING_BYTE, &stats->rx_bytes); + if (err) + goto error; + + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + DPSW_CNT_EGR_BYTE, &stats->tx_bytes); + if (err) + goto error; + + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + DPSW_CNT_ING_FRAME_DISCARD, + &stats->rx_dropped); + if (err) + goto error; + + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + DPSW_CNT_ING_FLTR_FRAME, + &tmp); + if (err) + goto error; + stats->rx_dropped += tmp; + + err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + DPSW_CNT_EGR_FRAME_DISCARD, + &stats->tx_dropped); + if (err) + goto error; + + return; + +error: + netdev_err(netdev, "dpsw_if_get_counter err %d\n", err); +} + +static bool port_has_offload_stats(const struct net_device *netdev, + int attr_id) +{ + return (attr_id == IFLA_OFFLOAD_XSTATS_CPU_HIT); +} + +static int port_get_offload_stats(int attr_id, + const struct net_device *netdev, + void *sp) +{ + switch (attr_id) { + case IFLA_OFFLOAD_XSTATS_CPU_HIT: + port_get_stats((struct net_device *)netdev, sp); + return 0; + } + + return -EINVAL; +} + +static int port_change_mtu(struct net_device *netdev, int mtu) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int err; + + err = dpsw_if_set_max_frame_length(port_priv->ethsw_data->mc_io, + 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, + (u16)ETHSW_L2_MAX_FRM(mtu)); + if (err) { + netdev_err(netdev, + "dpsw_if_set_max_frame_length() err %d\n", err); + return err; + } + + netdev->mtu = mtu; + return 0; +} + +static int port_carrier_state_sync(struct net_device *netdev) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + struct dpsw_link_state state; + int err; + + err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx, &state); + if (err) { + netdev_err(netdev, "dpsw_if_get_link_state() err %d\n", err); + return err; + } + + WARN_ONCE(state.up > 1, "Garbage read into link_state"); + + if (state.up != port_priv->link_state) { + if (state.up) + netif_carrier_on(netdev); + else + netif_carrier_off(netdev); + port_priv->link_state = state.up; + } + return 0; +} + +static int port_open(struct net_device *netdev) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int err; + + /* No need to allow Tx as control interface is disabled */ + netif_tx_stop_all_queues(netdev); + + err = dpsw_if_enable(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx); + if (err) { + netdev_err(netdev, "dpsw_if_enable err %d\n", err); + return err; + } + + /* sync carrier state */ + err = port_carrier_state_sync(netdev); + if (err) { + netdev_err(netdev, + "port_carrier_state_sync err %d\n", err); + goto err_carrier_sync; + } + + return 0; + +err_carrier_sync: + dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx); + return err; +} + +static int port_stop(struct net_device *netdev) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int err; + + err = dpsw_if_disable(port_priv->ethsw_data->mc_io, 0, + port_priv->ethsw_data->dpsw_handle, + port_priv->idx); + if (err) { + netdev_err(netdev, "dpsw_if_disable err %d\n", err); + return err; + } + + return 0; +} + +static netdev_tx_t port_dropframe(struct sk_buff *skb, + struct net_device *netdev) +{ + /* we don't support I/O for now, drop the frame */ + dev_kfree_skb_any(skb); + + return NETDEV_TX_OK; +} + +static const struct net_device_ops ethsw_port_ops = { + .ndo_open = port_open, + .ndo_stop = port_stop, + + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = port_change_mtu, + .ndo_has_offload_stats = port_has_offload_stats, + .ndo_get_offload_stats = port_get_offload_stats, + + .ndo_start_xmit = port_dropframe, +}; + +static void ethsw_links_state_update(struct ethsw_core *ethsw) +{ + int i; + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) + port_carrier_state_sync(ethsw->ports[i]->netdev); +} + +static irqreturn_t ethsw_irq0_handler_thread(int irq_num, void *arg) +{ + struct device *dev = (struct device *)arg; + struct ethsw_core *ethsw = dev_get_drvdata(dev); + + /* Mask the events and the if_id reserved bits to be cleared on read */ + u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000; + int err; + + err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, + DPSW_IRQ_INDEX_IF, &status); + if (err) { + dev_err(dev, "Can't get irq status (err %d)", err); + + err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle, + DPSW_IRQ_INDEX_IF, 0xFFFFFFFF); + if (err) + dev_err(dev, "Can't clear irq status (err %d)", err); + goto out; + } + + if (status & DPSW_IRQ_EVENT_LINK_CHANGED) + ethsw_links_state_update(ethsw); + +out: + return IRQ_HANDLED; +} + +static int ethsw_setup_irqs(struct fsl_mc_device *sw_dev) +{ + struct device *dev = &sw_dev->dev; + struct ethsw_core *ethsw = dev_get_drvdata(dev); + u32 mask = DPSW_IRQ_EVENT_LINK_CHANGED; + struct fsl_mc_device_irq *irq; + int err; + + err = fsl_mc_allocate_irqs(sw_dev); + if (err) { + dev_err(dev, "MC irqs allocation failed\n"); + return err; + } + + if (WARN_ON(sw_dev->obj_desc.irq_count != DPSW_IRQ_NUM)) { + err = -EINVAL; + goto free_irq; + } + + err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, + DPSW_IRQ_INDEX_IF, 0); + if (err) { + dev_err(dev, "dpsw_set_irq_enable err %d\n", err); + goto free_irq; + } + + irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF]; + + err = devm_request_threaded_irq(dev, irq->msi_desc->irq, + NULL, + ethsw_irq0_handler_thread, + IRQF_NO_SUSPEND | IRQF_ONESHOT, + dev_name(dev), dev); + if (err) { + dev_err(dev, "devm_request_threaded_irq(): %d", err); + goto free_irq; + } + + err = dpsw_set_irq_mask(ethsw->mc_io, 0, ethsw->dpsw_handle, + DPSW_IRQ_INDEX_IF, mask); + if (err) { + dev_err(dev, "dpsw_set_irq_mask(): %d", err); + goto free_devm_irq; + } + + err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, + DPSW_IRQ_INDEX_IF, 1); + if (err) { + dev_err(dev, "dpsw_set_irq_enable(): %d", err); + goto free_devm_irq; + } + + return 0; + +free_devm_irq: + devm_free_irq(dev, irq->msi_desc->irq, dev); +free_irq: + fsl_mc_free_irqs(sw_dev); + return err; +} + +static void ethsw_teardown_irqs(struct fsl_mc_device *sw_dev) +{ + struct device *dev = &sw_dev->dev; + struct ethsw_core *ethsw = dev_get_drvdata(dev); + struct fsl_mc_device_irq *irq; + int err; + + irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF]; + err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, + DPSW_IRQ_INDEX_IF, 0); + if (err) + dev_err(dev, "dpsw_set_irq_enable err %d\n", err); + + fsl_mc_free_irqs(sw_dev); +} + +static int swdev_port_attr_get(struct net_device *netdev, + struct switchdev_attr *attr) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: + attr->u.ppid.id_len = 1; + attr->u.ppid.id[0] = port_priv->ethsw_data->dev_id; + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + attr->u.brport_flags = + (port_priv->ethsw_data->learning ? BR_LEARNING : 0) | + (port_priv->flood ? BR_FLOOD : 0); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: + attr->u.brport_flags_support = BR_LEARNING | BR_FLOOD; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int port_attr_stp_state_set(struct net_device *netdev, + struct switchdev_trans *trans, + u8 state) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + return ethsw_port_set_stp_state(port_priv, state); +} + +static int port_attr_br_flags_set(struct net_device *netdev, + struct switchdev_trans *trans, + unsigned long flags) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int err = 0; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + /* Learning is enabled per switch */ + err = ethsw_set_learning(port_priv->ethsw_data, flags & BR_LEARNING); + if (err) + goto exit; + + err = ethsw_port_set_flood(port_priv, flags & BR_FLOOD); + +exit: + return err; +} + +static int swdev_port_attr_set(struct net_device *netdev, + const struct switchdev_attr *attr, + struct switchdev_trans *trans) +{ + int err = 0; + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: + err = port_attr_stp_state_set(netdev, trans, + attr->u.stp_state); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + err = port_attr_br_flags_set(netdev, trans, + attr->u.brport_flags); + break; + case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: + /* VLANs are supported by default */ + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int port_vlans_add(struct net_device *netdev, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int vid, err; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + if (!port_priv->ethsw_data->vlans[vid]) { + /* this is a new VLAN */ + err = ethsw_add_vlan(port_priv->ethsw_data, vid); + if (err) + return err; + + port_priv->ethsw_data->vlans[vid] |= ETHSW_VLAN_GLOBAL; + } + err = ethsw_port_add_vlan(port_priv, vid, vlan->flags); + if (err) + break; + } + + return err; +} + +static int port_lookup_address(struct net_device *netdev, int is_uc, + const unsigned char *addr) +{ + struct netdev_hw_addr_list *list = (is_uc) ? &netdev->uc : &netdev->mc; + struct netdev_hw_addr *ha; + + netif_addr_lock_bh(netdev); + list_for_each_entry(ha, &list->list, list) { + if (ether_addr_equal(ha->addr, addr)) { + netif_addr_unlock_bh(netdev); + return 1; + } + } + netif_addr_unlock_bh(netdev); + return 0; +} + +static int port_mdb_add(struct net_device *netdev, + const struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int err; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + /* Check if address is already set on this port */ + if (port_lookup_address(netdev, 0, mdb->addr)) + return -EEXIST; + + err = ethsw_port_fdb_add_mc(port_priv, mdb->addr); + if (err) + return err; + + err = dev_mc_add(netdev, mdb->addr); + if (err) { + netdev_err(netdev, "dev_mc_add err %d\n", err); + ethsw_port_fdb_del_mc(port_priv, mdb->addr); + } + + return err; +} + +static int swdev_port_obj_add(struct net_device *netdev, + const struct switchdev_obj *obj, + struct switchdev_trans *trans) +{ + int err; + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = port_vlans_add(netdev, + SWITCHDEV_OBJ_PORT_VLAN(obj), + trans); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + err = port_mdb_add(netdev, + SWITCHDEV_OBJ_PORT_MDB(obj), + trans); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int ethsw_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid) +{ + struct ethsw_core *ethsw = port_priv->ethsw_data; + struct net_device *netdev = port_priv->netdev; + struct dpsw_vlan_if_cfg vcfg; + int i, err; + + if (!port_priv->vlans[vid]) + return -ENOENT; + + if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) { + struct dpsw_tci_cfg tci_cfg = { 0 }; + + err = ethsw_port_set_tci(port_priv, &tci_cfg); + if (err) + return err; + } + + vcfg.num_ifs = 1; + vcfg.if_id[0] = port_priv->idx; + if (port_priv->vlans[vid] & ETHSW_VLAN_UNTAGGED) { + err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, + ethsw->dpsw_handle, + vid, &vcfg); + if (err) { + netdev_err(netdev, + "dpsw_vlan_remove_if_untagged err %d\n", + err); + } + port_priv->vlans[vid] &= ~ETHSW_VLAN_UNTAGGED; + } + + if (port_priv->vlans[vid] & ETHSW_VLAN_MEMBER) { + err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle, + vid, &vcfg); + if (err) { + netdev_err(netdev, + "dpsw_vlan_remove_if err %d\n", err); + return err; + } + port_priv->vlans[vid] &= ~ETHSW_VLAN_MEMBER; + + /* Delete VLAN from switch if it is no longer configured on + * any port + */ + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) + if (ethsw->ports[i]->vlans[vid] & ETHSW_VLAN_MEMBER) + return 0; /* Found a port member in VID */ + + ethsw->vlans[vid] &= ~ETHSW_VLAN_GLOBAL; + + err = ethsw_dellink_switch(ethsw, vid); + if (err) + return err; + } + + return 0; +} + +static int port_vlans_del(struct net_device *netdev, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int vid, err; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + err = ethsw_port_del_vlan(port_priv, vid); + if (err) + break; + } + + return err; +} + +static int port_mdb_del(struct net_device *netdev, + const struct switchdev_obj_port_mdb *mdb) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int err; + + if (!port_lookup_address(netdev, 0, mdb->addr)) + return -ENOENT; + + err = ethsw_port_fdb_del_mc(port_priv, mdb->addr); + if (err) + return err; + + err = dev_mc_del(netdev, mdb->addr); + if (err) { + netdev_err(netdev, "dev_mc_del err %d\n", err); + return err; + } + + return err; +} + +static int swdev_port_obj_del(struct net_device *netdev, + const struct switchdev_obj *obj) +{ + int err; + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = port_vlans_del(netdev, SWITCHDEV_OBJ_PORT_VLAN(obj)); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + err = port_mdb_del(netdev, SWITCHDEV_OBJ_PORT_MDB(obj)); + break; + default: + err = -EOPNOTSUPP; + break; + } + return err; +} + +static const struct switchdev_ops ethsw_port_switchdev_ops = { + .switchdev_port_attr_get = swdev_port_attr_get, + .switchdev_port_attr_set = swdev_port_attr_set, + .switchdev_port_obj_add = swdev_port_obj_add, + .switchdev_port_obj_del = swdev_port_obj_del, +}; + +/* For the moment, only flood setting needs to be updated */ +static int port_bridge_join(struct net_device *netdev, + struct net_device *upper_dev) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + struct ethsw_core *ethsw = port_priv->ethsw_data; + int i, err; + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) + if (ethsw->ports[i]->bridge_dev && + (ethsw->ports[i]->bridge_dev != upper_dev)) { + netdev_err(netdev, + "Another switch port is connected to %s\n", + ethsw->ports[i]->bridge_dev->name); + return -EINVAL; + } + + /* Enable flooding */ + err = ethsw_port_set_flood(port_priv, 1); + if (!err) + port_priv->bridge_dev = upper_dev; + + return err; +} + +static int port_bridge_leave(struct net_device *netdev) +{ + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + int err; + + /* Disable flooding */ + err = ethsw_port_set_flood(port_priv, 0); + if (!err) + port_priv->bridge_dev = NULL; + + return err; +} + +static int port_netdevice_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_changeupper_info *info = ptr; + struct net_device *upper_dev; + int err = 0; + + if (netdev->netdev_ops != ðsw_port_ops) + return NOTIFY_DONE; + + /* Handle just upper dev link/unlink for the moment */ + if (event == NETDEV_CHANGEUPPER) { + upper_dev = info->upper_dev; + if (netif_is_bridge_master(upper_dev)) { + if (info->linking) + err = port_bridge_join(netdev, upper_dev); + else + err = port_bridge_leave(netdev); + } + } + + return notifier_from_errno(err); +} + +static struct notifier_block port_nb __read_mostly = { + .notifier_call = port_netdevice_event, +}; + +struct ethsw_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct net_device *dev; + unsigned long event; +}; + +static void ethsw_switchdev_event_work(struct work_struct *work) +{ + struct ethsw_switchdev_event_work *switchdev_work = + container_of(work, struct ethsw_switchdev_event_work, work); + struct net_device *dev = switchdev_work->dev; + struct switchdev_notifier_fdb_info *fdb_info; + struct ethsw_port_priv *port_priv; + + rtnl_lock(); + port_priv = netdev_priv(dev); + fdb_info = &switchdev_work->fdb_info; + + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + if (is_unicast_ether_addr(fdb_info->addr)) + ethsw_port_fdb_add_uc(netdev_priv(dev), fdb_info->addr); + else + ethsw_port_fdb_add_mc(netdev_priv(dev), fdb_info->addr); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + if (is_unicast_ether_addr(fdb_info->addr)) + ethsw_port_fdb_del_uc(netdev_priv(dev), fdb_info->addr); + else + ethsw_port_fdb_del_mc(netdev_priv(dev), fdb_info->addr); + break; + } + + rtnl_unlock(); + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(dev); +} + +/* Called under rcu_read_lock() */ +static int port_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + struct ethsw_switchdev_event_work *switchdev_work; + struct switchdev_notifier_fdb_info *fdb_info = ptr; + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, ethsw_switchdev_event_work); + switchdev_work->dev = dev; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + if (!switchdev_work->fdb_info.addr) + goto err_addr_alloc; + + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + + /* Take a reference on the device to avoid being freed. */ + dev_hold(dev); + break; + default: + return NOTIFY_DONE; + } + + queue_work(ethsw_owq, &switchdev_work->work); + + return NOTIFY_DONE; + +err_addr_alloc: + kfree(switchdev_work); + return NOTIFY_BAD; +} + +static struct notifier_block port_switchdev_nb = { + .notifier_call = port_switchdev_event, +}; + +static int ethsw_register_notifier(struct device *dev) +{ + int err; + + err = register_netdevice_notifier(&port_nb); + if (err) { + dev_err(dev, "Failed to register netdev notifier\n"); + return err; + } + + err = register_switchdev_notifier(&port_switchdev_nb); + if (err) { + dev_err(dev, "Failed to register switchdev notifier\n"); + goto err_switchdev_nb; + } + + return 0; + +err_switchdev_nb: + unregister_netdevice_notifier(&port_nb); + return err; +} + +static int ethsw_open(struct ethsw_core *ethsw) +{ + struct ethsw_port_priv *port_priv = NULL; + int i, err; + + err = dpsw_enable(ethsw->mc_io, 0, ethsw->dpsw_handle); + if (err) { + dev_err(ethsw->dev, "dpsw_enable err %d\n", err); + return err; + } + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + port_priv = ethsw->ports[i]; + err = dev_open(port_priv->netdev); + if (err) { + netdev_err(port_priv->netdev, "dev_open err %d\n", err); + return err; + } + } + + return 0; +} + +static int ethsw_stop(struct ethsw_core *ethsw) +{ + struct ethsw_port_priv *port_priv = NULL; + int i, err; + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + port_priv = ethsw->ports[i]; + dev_close(port_priv->netdev); + } + + err = dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); + if (err) { + dev_err(ethsw->dev, "dpsw_disable err %d\n", err); + return err; + } + + return 0; +} + +static int ethsw_init(struct fsl_mc_device *sw_dev) +{ + struct device *dev = &sw_dev->dev; + struct ethsw_core *ethsw = dev_get_drvdata(dev); + u16 version_major, version_minor, i; + struct dpsw_stp_cfg stp_cfg; + int err; + + ethsw->dev_id = sw_dev->obj_desc.id; + + err = dpsw_open(ethsw->mc_io, 0, ethsw->dev_id, ðsw->dpsw_handle); + if (err) { + dev_err(dev, "dpsw_open err %d\n", err); + return err; + } + + err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle, + ðsw->sw_attr); + if (err) { + dev_err(dev, "dpsw_get_attributes err %d\n", err); + goto err_close; + } + + err = dpsw_get_api_version(ethsw->mc_io, 0, + &version_major, + &version_minor); + if (err) { + dev_err(dev, "dpsw_get_api_version err %d\n", err); + goto err_close; + } + + /* Minimum supported DPSW version check */ + if (version_major < DPSW_MIN_VER_MAJOR || + (version_major == DPSW_MIN_VER_MAJOR && + version_minor < DPSW_MIN_VER_MINOR)) { + dev_err(dev, "DPSW version %d:%d not supported. Use %d.%d or greater.\n", + version_major, + version_minor, + DPSW_MIN_VER_MAJOR, DPSW_MIN_VER_MINOR); + err = -ENOTSUPP; + goto err_close; + } + + err = dpsw_reset(ethsw->mc_io, 0, ethsw->dpsw_handle); + if (err) { + dev_err(dev, "dpsw_reset err %d\n", err); + goto err_close; + } + + err = dpsw_fdb_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle, 0, + DPSW_FDB_LEARNING_MODE_HW); + if (err) { + dev_err(dev, "dpsw_fdb_set_learning_mode err %d\n", err); + goto err_close; + } + + stp_cfg.vlan_id = DEFAULT_VLAN_ID; + stp_cfg.state = DPSW_STP_STATE_FORWARDING; + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + err = dpsw_if_set_stp(ethsw->mc_io, 0, ethsw->dpsw_handle, i, + &stp_cfg); + if (err) { + dev_err(dev, "dpsw_if_set_stp err %d for port %d\n", + err, i); + goto err_close; + } + + err = dpsw_if_set_broadcast(ethsw->mc_io, 0, + ethsw->dpsw_handle, i, 1); + if (err) { + dev_err(dev, + "dpsw_if_set_broadcast err %d for port %d\n", + err, i); + goto err_close; + } + } + + ethsw_owq = alloc_ordered_workqueue("%s_ordered", WQ_MEM_RECLAIM, + "ethsw"); + if (!ethsw_owq) { + err = -ENOMEM; + goto err_close; + } + + err = ethsw_register_notifier(dev); + if (err) + goto err_destroy_ordered_workqueue; + + return 0; + +err_destroy_ordered_workqueue: + destroy_workqueue(ethsw_owq); + +err_close: + dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); + return err; +} + +static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port) +{ + const char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01}; + struct net_device *netdev = port_priv->netdev; + struct ethsw_core *ethsw = port_priv->ethsw_data; + struct dpsw_tci_cfg tci_cfg = {0}; + struct dpsw_vlan_if_cfg vcfg; + int err; + + /* Switch starts with all ports configured to VLAN 1. Need to + * remove this setting to allow configuration at bridge join + */ + vcfg.num_ifs = 1; + vcfg.if_id[0] = port_priv->idx; + + err = dpsw_vlan_remove_if_untagged(ethsw->mc_io, 0, ethsw->dpsw_handle, + DEFAULT_VLAN_ID, &vcfg); + if (err) { + netdev_err(netdev, "dpsw_vlan_remove_if_untagged err %d\n", + err); + return err; + } + + err = ethsw_port_set_tci(port_priv, &tci_cfg); + if (err) + return err; + + err = dpsw_vlan_remove_if(ethsw->mc_io, 0, ethsw->dpsw_handle, + DEFAULT_VLAN_ID, &vcfg); + if (err) { + netdev_err(netdev, "dpsw_vlan_remove_if err %d\n", err); + return err; + } + + err = ethsw_port_fdb_add_mc(port_priv, def_mcast); + + return err; +} + +static void ethsw_unregister_notifier(struct device *dev) +{ + int err; + + err = unregister_switchdev_notifier(&port_switchdev_nb); + if (err) + dev_err(dev, + "Failed to unregister switchdev notifier (%d)\n", err); + + err = unregister_netdevice_notifier(&port_nb); + if (err) + dev_err(dev, + "Failed to unregister netdev notifier (%d)\n", err); +} + +static void ethsw_takedown(struct fsl_mc_device *sw_dev) +{ + struct device *dev = &sw_dev->dev; + struct ethsw_core *ethsw = dev_get_drvdata(dev); + int err; + + ethsw_unregister_notifier(dev); + + err = dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); + if (err) + dev_warn(dev, "dpsw_close err %d\n", err); +} + +static int ethsw_remove(struct fsl_mc_device *sw_dev) +{ + struct ethsw_port_priv *port_priv; + struct ethsw_core *ethsw; + struct device *dev; + int i; + + dev = &sw_dev->dev; + ethsw = dev_get_drvdata(dev); + + ethsw_teardown_irqs(sw_dev); + + destroy_workqueue(ethsw_owq); + + rtnl_lock(); + ethsw_stop(ethsw); + rtnl_unlock(); + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + port_priv = ethsw->ports[i]; + unregister_netdev(port_priv->netdev); + free_netdev(port_priv->netdev); + } + kfree(ethsw->ports); + + ethsw_takedown(sw_dev); + fsl_mc_portal_free(ethsw->mc_io); + + kfree(ethsw); + + dev_set_drvdata(dev, NULL); + + return 0; +} + +static int ethsw_probe_port(struct ethsw_core *ethsw, u16 port_idx) +{ + struct ethsw_port_priv *port_priv; + struct device *dev = ethsw->dev; + struct net_device *port_netdev; + int err; + + port_netdev = alloc_etherdev(sizeof(struct ethsw_port_priv)); + if (!port_netdev) { + dev_err(dev, "alloc_etherdev error\n"); + return -ENOMEM; + } + + port_priv = netdev_priv(port_netdev); + port_priv->netdev = port_netdev; + port_priv->ethsw_data = ethsw; + + port_priv->idx = port_idx; + port_priv->stp_state = BR_STATE_FORWARDING; + + /* Flooding is implicitly enabled */ + port_priv->flood = true; + + SET_NETDEV_DEV(port_netdev, dev); + port_netdev->netdev_ops = ðsw_port_ops; + port_netdev->ethtool_ops = ðsw_port_ethtool_ops; + port_netdev->switchdev_ops = ðsw_port_switchdev_ops; + + /* Set MTU limits */ + port_netdev->min_mtu = ETH_MIN_MTU; + port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH; + + err = register_netdev(port_netdev); + if (err < 0) { + dev_err(dev, "register_netdev error %d\n", err); + free_netdev(port_netdev); + return err; + } + + ethsw->ports[port_idx] = port_priv; + + return ethsw_port_init(port_priv, port_idx); +} + +static int ethsw_probe(struct fsl_mc_device *sw_dev) +{ + struct device *dev = &sw_dev->dev; + struct ethsw_core *ethsw; + int i, err; + + /* Allocate switch core*/ + ethsw = kzalloc(sizeof(*ethsw), GFP_KERNEL); + + if (!ethsw) + return -ENOMEM; + + ethsw->dev = dev; + dev_set_drvdata(dev, ethsw); + + err = fsl_mc_portal_allocate(sw_dev, 0, ðsw->mc_io); + if (err) { + if (err == -ENXIO) + err = -EPROBE_DEFER; + else + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); + goto err_free_drvdata; + } + + err = ethsw_init(sw_dev); + if (err) + goto err_free_cmdport; + + /* DEFAULT_VLAN_ID is implicitly configured on the switch */ + ethsw->vlans[DEFAULT_VLAN_ID] = ETHSW_VLAN_MEMBER; + + /* Learning is implicitly enabled */ + ethsw->learning = true; + + ethsw->ports = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->ports), + GFP_KERNEL); + if (!(ethsw->ports)) { + err = -ENOMEM; + goto err_takedown; + } + + for (i = 0; i < ethsw->sw_attr.num_ifs; i++) { + err = ethsw_probe_port(ethsw, i); + if (err) + goto err_free_ports; + } + + /* Switch starts up enabled */ + rtnl_lock(); + err = ethsw_open(ethsw); + rtnl_unlock(); + if (err) + goto err_free_ports; + + /* Setup IRQs */ + err = ethsw_setup_irqs(sw_dev); + if (err) + goto err_stop; + + dev_info(dev, "probed %d port switch\n", ethsw->sw_attr.num_ifs); + return 0; + +err_stop: + rtnl_lock(); + ethsw_stop(ethsw); + rtnl_unlock(); + +err_free_ports: + /* Cleanup registered ports only */ + for (i--; i >= 0; i--) { + unregister_netdev(ethsw->ports[i]->netdev); + free_netdev(ethsw->ports[i]->netdev); + } + kfree(ethsw->ports); + +err_takedown: + ethsw_takedown(sw_dev); + +err_free_cmdport: + fsl_mc_portal_free(ethsw->mc_io); + +err_free_drvdata: + kfree(ethsw); + dev_set_drvdata(dev, NULL); + + return err; +} + +static const struct fsl_mc_device_id ethsw_match_id_table[] = { + { + .vendor = FSL_MC_VENDOR_FREESCALE, + .obj_type = "dpsw", + }, + { .vendor = 0x0 } +}; +MODULE_DEVICE_TABLE(fslmc, ethsw_match_id_table); + +static struct fsl_mc_driver eth_sw_drv = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = ethsw_probe, + .remove = ethsw_remove, + .match_id_table = ethsw_match_id_table +}; + +module_fsl_mc_driver(eth_sw_drv); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DPAA2 Ethernet Switch Driver"); diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.h b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h new file mode 100644 index 000000000000..069c99bfba74 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DPAA2 Ethernet Switch declarations + * + * Copyright 2014-2016 Freescale Semiconductor Inc. + * Copyright 2017-2018 NXP + * + */ + +#ifndef __ETHSW_H +#define __ETHSW_H + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/rtnetlink.h> +#include <linux/if_vlan.h> +#include <uapi/linux/if_bridge.h> +#include <net/switchdev.h> +#include <linux/if_bridge.h> + +#include "dpsw.h" + +/* Number of IRQs supported */ +#define DPSW_IRQ_NUM 2 + +#define ETHSW_VLAN_MEMBER 1 +#define ETHSW_VLAN_UNTAGGED 2 +#define ETHSW_VLAN_PVID 4 +#define ETHSW_VLAN_GLOBAL 8 + +/* Maximum Frame Length supported by HW (currently 10k) */ +#define DPAA2_MFL (10 * 1024) +#define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN) +#define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN) + +extern const struct ethtool_ops ethsw_port_ethtool_ops; + +struct ethsw_core; + +/* Per port private data */ +struct ethsw_port_priv { + struct net_device *netdev; + u16 idx; + struct ethsw_core *ethsw_data; + u8 link_state; + u8 stp_state; + bool flood; + + u8 vlans[VLAN_VID_MASK + 1]; + u16 pvid; + struct net_device *bridge_dev; +}; + +/* Switch data */ +struct ethsw_core { + struct device *dev; + struct fsl_mc_io *mc_io; + u16 dpsw_handle; + struct dpsw_attr sw_attr; + int dev_id; + struct ethsw_port_priv **ports; + + u8 vlans[VLAN_VID_MASK + 1]; + bool learning; +}; + +#endif /* __ETHSW_H */ diff --git a/drivers/staging/fsl-mc/TODO b/drivers/staging/fsl-mc/TODO deleted file mode 100644 index 54a8bc69222e..000000000000 --- a/drivers/staging/fsl-mc/TODO +++ /dev/null @@ -1,18 +0,0 @@ -* Add at least one device driver for a DPAA2 object (child device of the - fsl-mc bus). Most likely candidate for this is adding DPAA2 Ethernet - driver support, which depends on drivers for several objects: DPNI, - DPIO, DPMAC. Other pre-requisites include: - - * MC firmware uprev. The MC firmware upon which the fsl-mc - bus driver and DPAA2 object drivers are based is continuing - to evolve, so minor updates are needed to keep in sync with binary - interface changes to the MC. - -* Cleanup - -Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org>, -german.rivera@freescale.com, devel@driverdev.osuosl.org, -linux-kernel@vger.kernel.org - -[1] https://lkml.org/lkml/2015/7/9/93 -[2] https://lkml.org/lkml/2015/7/7/712 diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig index b35ef7ee6901..342453035269 100644 --- a/drivers/staging/fsl-mc/bus/Kconfig +++ b/drivers/staging/fsl-mc/bus/Kconfig @@ -5,19 +5,9 @@ # Copyright (C) 2014-2016 Freescale Semiconductor, Inc. # -config FSL_MC_BUS - bool "QorIQ DPAA2 fsl-mc bus driver" - depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC))) - select GENERIC_MSI_IRQ_DOMAIN - help - Driver to enable the bus infrastructure for the QorIQ DPAA2 - architecture. The fsl-mc bus driver handles discovery of - DPAA2 objects (which are represented as Linux devices) and - binding objects to drivers. - config FSL_MC_DPIO tristate "QorIQ DPAA2 DPIO driver" - depends on FSL_MC_BUS && ARCH_LAYERSCAPE + depends on FSL_MC_BUS help Driver for the DPAA2 DPIO object. A DPIO provides queue and buffer management facilities for software to interact with diff --git a/drivers/staging/fsl-mc/bus/Makefile b/drivers/staging/fsl-mc/bus/Makefile index 29059db95ecc..21d8ebc8ce21 100644 --- a/drivers/staging/fsl-mc/bus/Makefile +++ b/drivers/staging/fsl-mc/bus/Makefile @@ -4,19 +4,6 @@ # # Copyright (C) 2014 Freescale Semiconductor, Inc. # -obj-$(CONFIG_FSL_MC_BUS) += mc-bus-driver.o - -mc-bus-driver-objs := fsl-mc-bus.o \ - mc-sys.o \ - mc-io.o \ - dprc.o \ - dprc-driver.o \ - fsl-mc-allocator.o \ - fsl-mc-msi.o \ - irq-gic-v3-its-fsl-mc-msi.o \ - dpmcp.o \ - dpbp.o \ - dpcon.o # MC DPIO driver obj-$(CONFIG_FSL_MC_DPIO) += dpio/ diff --git a/drivers/staging/fsl-mc/bus/dpbp-cmd.h b/drivers/staging/fsl-mc/bus/dpbp-cmd.h deleted file mode 100644 index 0b7f5c041f19..000000000000 --- a/drivers/staging/fsl-mc/bus/dpbp-cmd.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2013-2016 Freescale Semiconductor Inc. - * - */ -#ifndef _FSL_DPBP_CMD_H -#define _FSL_DPBP_CMD_H - -/* DPBP Version */ -#define DPBP_VER_MAJOR 3 -#define DPBP_VER_MINOR 2 - -/* Command versioning */ -#define DPBP_CMD_BASE_VERSION 1 -#define DPBP_CMD_ID_OFFSET 4 - -#define DPBP_CMD(id) (((id) << DPBP_CMD_ID_OFFSET) | DPBP_CMD_BASE_VERSION) - -/* Command IDs */ -#define DPBP_CMDID_CLOSE DPBP_CMD(0x800) -#define DPBP_CMDID_OPEN DPBP_CMD(0x804) -#define DPBP_CMDID_GET_API_VERSION DPBP_CMD(0xa04) - -#define DPBP_CMDID_ENABLE DPBP_CMD(0x002) -#define DPBP_CMDID_DISABLE DPBP_CMD(0x003) -#define DPBP_CMDID_GET_ATTR DPBP_CMD(0x004) -#define DPBP_CMDID_RESET DPBP_CMD(0x005) -#define DPBP_CMDID_IS_ENABLED DPBP_CMD(0x006) - -struct dpbp_cmd_open { - __le32 dpbp_id; -}; - -struct dpbp_cmd_destroy { - __le32 object_id; -}; - -#define DPBP_ENABLE 0x1 - -struct dpbp_rsp_is_enabled { - u8 enabled; -}; - -struct dpbp_rsp_get_attributes { - /* response word 0 */ - __le16 pad; - __le16 bpid; - __le32 id; - /* response word 1 */ - __le16 version_major; - __le16 version_minor; -}; - -#endif /* _FSL_DPBP_CMD_H */ diff --git a/drivers/staging/fsl-mc/bus/dpcon-cmd.h b/drivers/staging/fsl-mc/bus/dpcon-cmd.h deleted file mode 100644 index 27fa09877970..000000000000 --- a/drivers/staging/fsl-mc/bus/dpcon-cmd.h +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2013-2016 Freescale Semiconductor Inc. - * - */ -#ifndef _FSL_DPCON_CMD_H -#define _FSL_DPCON_CMD_H - -/* DPCON Version */ -#define DPCON_VER_MAJOR 3 -#define DPCON_VER_MINOR 2 - -/* Command versioning */ -#define DPCON_CMD_BASE_VERSION 1 -#define DPCON_CMD_ID_OFFSET 4 - -#define DPCON_CMD(id) (((id) << DPCON_CMD_ID_OFFSET) | DPCON_CMD_BASE_VERSION) - -/* Command IDs */ -#define DPCON_CMDID_CLOSE DPCON_CMD(0x800) -#define DPCON_CMDID_OPEN DPCON_CMD(0x808) - -#define DPCON_CMDID_ENABLE DPCON_CMD(0x002) -#define DPCON_CMDID_DISABLE DPCON_CMD(0x003) -#define DPCON_CMDID_GET_ATTR DPCON_CMD(0x004) -#define DPCON_CMDID_RESET DPCON_CMD(0x005) - -#define DPCON_CMDID_SET_NOTIFICATION DPCON_CMD(0x100) - -struct dpcon_cmd_open { - __le32 dpcon_id; -}; - -#define DPCON_ENABLE 1 - -struct dpcon_rsp_get_attr { - /* response word 0 */ - __le32 id; - __le16 qbman_ch_id; - u8 num_priorities; - u8 pad; -}; - -struct dpcon_cmd_set_notification { - /* cmd word 0 */ - __le32 dpio_id; - u8 priority; - u8 pad[3]; - /* cmd word 1 */ - __le64 user_ctx; -}; - -#endif /* _FSL_DPCON_CMD_H */ diff --git a/drivers/staging/fsl-mc/bus/dpio/Makefile b/drivers/staging/fsl-mc/bus/dpio/Makefile index 53ba84d7b884..b9ff24c76582 100644 --- a/drivers/staging/fsl-mc/bus/dpio/Makefile +++ b/drivers/staging/fsl-mc/bus/dpio/Makefile @@ -3,8 +3,6 @@ # QorIQ DPAA2 DPIO driver # -subdir-ccflags-y := -Werror - obj-$(CONFIG_FSL_MC_DPIO) += fsl-mc-dpio.o fsl-mc-dpio-objs := dpio.o qbman-portal.o dpio-service.o dpio-driver.o diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c index b8479ef64c71..182b38412a82 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c +++ b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c @@ -14,7 +14,7 @@ #include <linux/dma-mapping.h> #include <linux/delay.h> -#include "../../include/mc.h" +#include <linux/fsl/mc.h> #include "../../include/dpaa2-io.h" #include "qbman-portal.h" diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c index d3c8462d43e8..14ed2beb7432 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c +++ b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c @@ -5,7 +5,7 @@ * */ #include <linux/types.h> -#include "../../include/mc.h" +#include <linux/fsl/mc.h> #include "../../include/dpaa2-io.h" #include <linux/init.h> #include <linux/module.h> @@ -192,7 +192,7 @@ irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj) u64 q64; q64 = qbman_result_SCN_ctx(dq); - ctx = (void *)q64; + ctx = (void *)(uintptr_t)q64; ctx->cb(ctx); } else { pr_crit("fsl-mc-dpio: Unrecognised/ignored DQRR entry\n"); @@ -237,7 +237,7 @@ int dpaa2_io_service_register(struct dpaa2_io *d, return -ENODEV; ctx->dpio_id = d->dpio_desc.dpio_id; - ctx->qman64 = (u64)ctx; + ctx->qman64 = (u64)(uintptr_t)ctx; ctx->dpio_private = d; spin_lock_irqsave(&d->lock_notifications, irqflags); list_add(&ctx->node, &d->notifications); diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.c b/drivers/staging/fsl-mc/bus/dpio/dpio.c index 20cdeae54a74..ff37c80e11a0 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio.c +++ b/drivers/staging/fsl-mc/bus/dpio/dpio.c @@ -5,7 +5,7 @@ * */ #include <linux/kernel.h> -#include "../../include/mc.h" +#include <linux/fsl/mc.h> #include "dpio.h" #include "dpio-cmd.h" @@ -37,7 +37,7 @@ int dpio_open(struct fsl_mc_io *mc_io, int dpio_id, u16 *token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpio_cmd_open *dpio_cmd; int err; @@ -70,7 +70,7 @@ int dpio_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPIO_CMDID_CLOSE, @@ -92,7 +92,7 @@ int dpio_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPIO_CMDID_ENABLE, @@ -114,7 +114,7 @@ int dpio_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; /* prepare command */ cmd.header = mc_encode_cmd_header(DPIO_CMDID_DISABLE, @@ -138,7 +138,7 @@ int dpio_get_attributes(struct fsl_mc_io *mc_io, u16 token, struct dpio_attr *attr) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; struct dpio_rsp_get_attr *dpio_rsp; int err; @@ -180,7 +180,7 @@ int dpio_get_api_version(struct fsl_mc_io *mc_io, u16 *major_ver, u16 *minor_ver) { - struct mc_command cmd = { 0 }; + struct fsl_mc_command cmd = { 0 }; int err; /* prepare command */ diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c index 376e9ed0297a..116fafb28640 100644 --- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c +++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c @@ -497,7 +497,7 @@ void qbman_pull_desc_set_storage(struct qbman_pull_desc *d, int stash) { /* save the virtual address */ - d->rsp_addr_virt = (u64)storage; + d->rsp_addr_virt = (u64)(uintptr_t)storage; if (!storage) { d->verb &= ~(1 << QB_VDQCR_VERB_RLS_SHIFT); @@ -522,11 +522,6 @@ void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, u8 numframes) d->numf = numframes - 1; } -void qbman_pull_desc_set_token(struct qbman_pull_desc *d, u8 token) -{ - d->tok = token; -} - /* * Exactly one of the following descriptor "actions" should be set. (Calling any * one of these will replace the effect of any prior call to one of these.) @@ -590,7 +585,7 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d) atomic_inc(&s->vdq.available); return -EBUSY; } - s->vdq.storage = (void *)d->rsp_addr_virt; + s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt; p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); p->numf = d->numf; p->tok = QMAN_DQ_TOKEN_VALID; @@ -830,7 +825,7 @@ int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, struct qbman_acquire_desc { u8 verb; u8 reserved; - u16 bpid; + __le16 bpid; u8 num; u8 reserved2[59]; }; @@ -838,10 +833,10 @@ struct qbman_acquire_desc { struct qbman_acquire_rslt { u8 verb; u8 rslt; - u16 reserved; + __le16 reserved; u8 num; u8 reserved2[3]; - u64 buf[7]; + __le64 buf[7]; }; /** @@ -904,7 +899,7 @@ int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers, struct qbman_alt_fq_state_desc { u8 verb; u8 reserved[3]; - u32 fqid; + __le32 fqid; u8 reserved2[56]; }; @@ -927,7 +922,7 @@ int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid, if (!p) return -EBUSY; - p->fqid = cpu_to_le32(fqid) & ALT_FQ_FQID_MASK; + p->fqid = cpu_to_le32(fqid & ALT_FQ_FQID_MASK); /* Complete the management command */ r = qbman_swp_mc_complete(s, p, alt_fq_verb); @@ -953,11 +948,11 @@ int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid, struct qbman_cdan_ctrl_desc { u8 verb; u8 reserved; - u16 ch; + __le16 ch; u8 we; u8 ctrl; - u16 reserved2; - u64 cdan_ctx; + __le16 reserved2; + __le64 cdan_ctx; u8 reserved3[48]; }; @@ -965,7 +960,7 @@ struct qbman_cdan_ctrl_desc { struct qbman_cdan_ctrl_rslt { u8 verb; u8 rslt; - u16 ch; + __le16 ch; u8 reserved[60]; }; diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h index fb8b9d35a3eb..4488a445b709 100644 --- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h +++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h @@ -32,8 +32,8 @@ struct qbman_pull_desc { u8 numf; u8 tok; u8 reserved; - u32 dq_src; - u64 rsp_addr; + __le32 dq_src; + __le64 rsp_addr; u64 rsp_addr_virt; u8 padding[40]; }; @@ -70,17 +70,17 @@ enum qbman_pull_type_e { struct qbman_eq_desc { u8 verb; u8 dca; - u16 seqnum; - u16 orpid; - u16 reserved1; - u32 tgtid; - u32 tag; - u16 qdbin; + __le16 seqnum; + __le16 orpid; + __le16 reserved1; + __le32 tgtid; + __le32 tag; + __le16 qdbin; u8 qpri; u8 reserved[3]; u8 wae; u8 rspid; - u64 rsp_addr; + __le64 rsp_addr; u8 fd[32]; }; @@ -88,9 +88,9 @@ struct qbman_eq_desc { struct qbman_release_desc { u8 verb; u8 reserved; - u16 bpid; - u32 reserved2; - u64 buf[7]; + __le16 bpid; + __le32 reserved2; + __le64 buf[7]; }; /* Management command result codes */ diff --git a/drivers/staging/fsl-mc/include/dpaa2-fd.h b/drivers/staging/fsl-mc/include/dpaa2-fd.h index 3e022001f0b1..b55b89ba4eda 100644 --- a/drivers/staging/fsl-mc/include/dpaa2-fd.h +++ b/drivers/staging/fsl-mc/include/dpaa2-fd.h @@ -287,7 +287,7 @@ enum dpaa2_sg_format { */ static inline dma_addr_t dpaa2_sg_get_addr(const struct dpaa2_sg_entry *sg) { - return le64_to_cpu((dma_addr_t)sg->addr); + return (dma_addr_t)le64_to_cpu(sg->addr); } /** @@ -418,8 +418,8 @@ static inline bool dpaa2_sg_is_final(const struct dpaa2_sg_entry *sg) */ static inline void dpaa2_sg_set_final(struct dpaa2_sg_entry *sg, bool final) { - sg->format_offset &= cpu_to_le16(~(SG_FINAL_FLAG_MASK - << SG_FINAL_FLAG_SHIFT)); + sg->format_offset &= cpu_to_le16((~(SG_FINAL_FLAG_MASK + << SG_FINAL_FLAG_SHIFT)) & 0xFFFF); sg->format_offset |= cpu_to_le16(final << SG_FINAL_FLAG_SHIFT); } diff --git a/drivers/staging/fsl-mc/include/dpaa2-io.h b/drivers/staging/fsl-mc/include/dpaa2-io.h index 9cb1eec87a9c..f71227d3df8d 100644 --- a/drivers/staging/fsl-mc/include/dpaa2-io.h +++ b/drivers/staging/fsl-mc/include/dpaa2-io.h @@ -80,7 +80,7 @@ struct dpaa2_io *dpaa2_io_service_select(int cpu); * Used when a FQDAN/CDAN registration is made by drivers. */ struct dpaa2_io_notification_ctx { - void (*cb)(struct dpaa2_io_notification_ctx *); + void (*cb)(struct dpaa2_io_notification_ctx *ctx); int is_cdan; u32 id; int desired_cpu; diff --git a/drivers/staging/fsl-mc/include/dpbp.h b/drivers/staging/fsl-mc/include/dpbp.h deleted file mode 100644 index 4a1809604319..000000000000 --- a/drivers/staging/fsl-mc/include/dpbp.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2013-2016 Freescale Semiconductor Inc. - * - */ -#ifndef __FSL_DPBP_H -#define __FSL_DPBP_H - -/* - * Data Path Buffer Pool API - * Contains initialization APIs and runtime control APIs for DPBP - */ - -struct fsl_mc_io; - -int dpbp_open(struct fsl_mc_io *mc_io, - u32 cmd_flags, - int dpbp_id, - u16 *token); - -int dpbp_close(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpbp_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpbp_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpbp_is_enabled(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - int *en); - -int dpbp_reset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -/** - * struct dpbp_attr - Structure representing DPBP attributes - * @id: DPBP object ID - * @bpid: Hardware buffer pool ID; should be used as an argument in - * acquire/release operations on buffers - */ -struct dpbp_attr { - int id; - u16 bpid; -}; - -int dpbp_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dpbp_attr *attr); - -int dpbp_get_api_version(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 *major_ver, - u16 *minor_ver); - -#endif /* __FSL_DPBP_H */ diff --git a/drivers/staging/fsl-mc/include/dpcon.h b/drivers/staging/fsl-mc/include/dpcon.h deleted file mode 100644 index 062e90ad929b..000000000000 --- a/drivers/staging/fsl-mc/include/dpcon.h +++ /dev/null @@ -1,79 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2013-2016 Freescale Semiconductor Inc. - * - */ -#ifndef __FSL_DPCON_H -#define __FSL_DPCON_H - -/* Data Path Concentrator API - * Contains initialization APIs and runtime control APIs for DPCON - */ - -struct fsl_mc_io; - -/** General DPCON macros */ - -/** - * Use it to disable notifications; see dpcon_set_notification() - */ -#define DPCON_INVALID_DPIO_ID (int)(-1) - -int dpcon_open(struct fsl_mc_io *mc_io, - u32 cmd_flags, - int dpcon_id, - u16 *token); - -int dpcon_close(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpcon_enable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpcon_disable(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -int dpcon_reset(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token); - -/** - * struct dpcon_attr - Structure representing DPCON attributes - * @id: DPCON object ID - * @qbman_ch_id: Channel ID to be used by dequeue operation - * @num_priorities: Number of priorities for the DPCON channel (1-8) - */ -struct dpcon_attr { - int id; - u16 qbman_ch_id; - u8 num_priorities; -}; - -int dpcon_get_attributes(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dpcon_attr *attr); - -/** - * struct dpcon_notification_cfg - Structure representing notification params - * @dpio_id: DPIO object ID; must be configured with a notification channel; - * to disable notifications set it to 'DPCON_INVALID_DPIO_ID'; - * @priority: Priority selection within the DPIO channel; valid values - * are 0-7, depending on the number of priorities in that channel - * @user_ctx: User context value provided with each CDAN message - */ -struct dpcon_notification_cfg { - int dpio_id; - u8 priority; - u64 user_ctx; -}; - -int dpcon_set_notification(struct fsl_mc_io *mc_io, - u32 cmd_flags, - u16 token, - struct dpcon_notification_cfg *cfg); - -#endif /* __FSL_DPCON_H */ diff --git a/drivers/staging/gdm724x/gdm_endian.c b/drivers/staging/gdm724x/gdm_endian.c index d0b43e20ec06..4200391b1a97 100644 --- a/drivers/staging/gdm724x/gdm_endian.c +++ b/drivers/staging/gdm724x/gdm_endian.c @@ -14,41 +14,33 @@ #include <linux/kernel.h> #include "gdm_endian.h" -void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian) +__dev16 gdm_cpu_to_dev16(u8 dev_ed, u16 x) { - if (dev_endian == ENDIANNESS_BIG) - ed->dev_ed = ENDIANNESS_BIG; - else - ed->dev_ed = ENDIANNESS_LITTLE; -} - -__dev16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x) -{ - if (ed->dev_ed == ENDIANNESS_LITTLE) + if (dev_ed == ENDIANNESS_LITTLE) return (__force __dev16)cpu_to_le16(x); else return (__force __dev16)cpu_to_be16(x); } -u16 gdm_dev16_to_cpu(struct gdm_endian *ed, __dev16 x) +u16 gdm_dev16_to_cpu(u8 dev_ed, __dev16 x) { - if (ed->dev_ed == ENDIANNESS_LITTLE) + if (dev_ed == ENDIANNESS_LITTLE) return le16_to_cpu((__force __le16)x); else return be16_to_cpu((__force __be16)x); } -__dev32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x) +__dev32 gdm_cpu_to_dev32(u8 dev_ed, u32 x) { - if (ed->dev_ed == ENDIANNESS_LITTLE) + if (dev_ed == ENDIANNESS_LITTLE) return (__force __dev32)cpu_to_le32(x); else return (__force __dev32)cpu_to_be32(x); } -u32 gdm_dev32_to_cpu(struct gdm_endian *ed, __dev32 x) +u32 gdm_dev32_to_cpu(u8 dev_ed, __dev32 x) { - if (ed->dev_ed == ENDIANNESS_LITTLE) + if (dev_ed == ENDIANNESS_LITTLE) return le32_to_cpu((__force __le32)x); else return be32_to_cpu((__force __be32)x); diff --git a/drivers/staging/gdm724x/gdm_endian.h b/drivers/staging/gdm724x/gdm_endian.h index a785f30bb369..e58d29f868ba 100644 --- a/drivers/staging/gdm724x/gdm_endian.h +++ b/drivers/staging/gdm724x/gdm_endian.h @@ -32,14 +32,9 @@ enum { ENDIANNESS_MAX }; -struct gdm_endian { - u8 dev_ed; -}; - -void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian); -__dev16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x); -u16 gdm_dev16_to_cpu(struct gdm_endian *ed, __dev16 x); -__dev32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x); -u32 gdm_dev32_to_cpu(struct gdm_endian *ed, __dev32 x); +__dev16 gdm_cpu_to_dev16(u8 dev_ed, u16 x); +u16 gdm_dev16_to_cpu(u8 dev_ed, __dev16 x); +__dev32 gdm_cpu_to_dev32(u8 dev_ed, u32 x); +u32 gdm_dev32_to_cpu(u8 dev_ed, __dev32 x); #endif /*__GDM_ENDIAN_H__*/ diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c index 0527b0d1c1d0..4f3c518304f2 100644 --- a/drivers/staging/gdm724x/gdm_lte.c +++ b/drivers/staging/gdm724x/gdm_lte.c @@ -185,6 +185,7 @@ static __sum16 icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len) unsigned short *w = ptr; __wsum sum = 0; int i; + u16 pa; union { struct { @@ -204,9 +205,10 @@ static __sum16 icmp6_checksum(struct ipv6hdr *ipv6, u16 *ptr, int len) pseudo_header.ph.ph_nxt = ipv6->nexthdr; w = (u16 *)&pseudo_header; - for (i = 0; i < ARRAY_SIZE(pseudo_header.pa); i++) - sum = csum_add(sum, csum_unfold( - (__force __sum16)pseudo_header.pa[i])); + for (i = 0; i < ARRAY_SIZE(pseudo_header.pa); i++) { + pa = pseudo_header.pa[i]; + sum = csum_add(sum, csum_unfold((__force __sum16)pa)); + } w = ptr; while (len > 1) { @@ -308,7 +310,8 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type) sizeof(struct neighbour_advertisement)); icmp6_out.icmp6_cksum = icmp6_checksum(&ipv6_out, - (u16 *)icmp_na, sizeof(icmp_na)); + (u16 *)icmp_na, + sizeof(icmp_na)); } else { return -EINVAL; } @@ -508,8 +511,9 @@ static struct net_device_stats *gdm_lte_stats(struct net_device *dev) static int gdm_lte_event_send(struct net_device *dev, char *buf, int len) { - struct nic *nic = netdev_priv(dev); + struct phy_dev *phy_dev = ((struct nic *)netdev_priv(dev))->phy_dev; struct hci_packet *hci = (struct hci_packet *)buf; + int length; int idx; int ret; @@ -517,11 +521,9 @@ static int gdm_lte_event_send(struct net_device *dev, char *buf, int len) if (ret != 1) return -EINVAL; - return netlink_send(lte_event.sock, idx, 0, buf, - gdm_dev16_to_cpu( - nic->phy_dev->get_endian( - nic->phy_dev->priv_dev), hci->len) - + HCI_HEADER_SIZE); + length = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev), + hci->len) + HCI_HEADER_SIZE; + return netlink_send(lte_event.sock, idx, 0, buf, length); } static void gdm_lte_event_rcv(struct net_device *dev, u16 type, @@ -683,7 +685,7 @@ static void gdm_lte_multi_sdu_pkt(struct phy_dev *phy_dev, char *buf, int len) struct net_device *dev; struct multi_sdu *multi_sdu = (struct multi_sdu *)buf; struct sdu *sdu = NULL; - struct gdm_endian *endian = phy_dev->get_endian(phy_dev->priv_dev); + u8 endian = phy_dev->get_endian(phy_dev->priv_dev); u8 *data = (u8 *)multi_sdu->data; u16 i = 0; u16 num_packet; @@ -728,33 +730,30 @@ static void gdm_lte_pdn_table(struct net_device *dev, char *buf, int len) { struct nic *nic = netdev_priv(dev); struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf; + u8 ed = nic->phy_dev->get_endian(nic->phy_dev->priv_dev); - if (pdn_table->activate) { - nic->pdn_table.activate = pdn_table->activate; - nic->pdn_table.dft_eps_id = gdm_dev32_to_cpu( - nic->phy_dev->get_endian( - nic->phy_dev->priv_dev), - pdn_table->dft_eps_id); - nic->pdn_table.nic_type = gdm_dev32_to_cpu( - nic->phy_dev->get_endian( - nic->phy_dev->priv_dev), - pdn_table->nic_type); - - netdev_info(dev, "pdn activated, nic_type=0x%x\n", - nic->pdn_table.nic_type); - } else { + if (!pdn_table->activate) { memset(&nic->pdn_table, 0x00, sizeof(struct pdn_table)); netdev_info(dev, "pdn deactivated\n"); + + return; } + + nic->pdn_table.activate = pdn_table->activate; + nic->pdn_table.dft_eps_id = gdm_dev32_to_cpu(ed, pdn_table->dft_eps_id); + nic->pdn_table.nic_type = gdm_dev32_to_cpu(ed, pdn_table->nic_type); + + netdev_info(dev, "pdn activated, nic_type=0x%x\n", + nic->pdn_table.nic_type); } static int gdm_lte_receive_pkt(struct phy_dev *phy_dev, char *buf, int len) { struct hci_packet *hci = (struct hci_packet *)buf; struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf; - struct gdm_endian *endian = phy_dev->get_endian(phy_dev->priv_dev); struct sdu *sdu; struct net_device *dev; + u8 endian = phy_dev->get_endian(phy_dev->priv_dev); int ret = 0; u16 cmd_evt; u32 nic_type; @@ -896,12 +895,11 @@ int register_lte_device(struct phy_dev *phy_dev, nic->phy_dev = phy_dev; nic->nic_id = index; - form_mac_address( - net->dev_addr, - nic->src_mac_addr, - nic->dest_mac_addr, - mac_address, - index); + form_mac_address(net->dev_addr, + nic->src_mac_addr, + nic->dest_mac_addr, + mac_address, + index); SET_NETDEV_DEV(net, dev); SET_NETDEV_DEVTYPE(net, &wwan_type); diff --git a/drivers/staging/gdm724x/gdm_lte.h b/drivers/staging/gdm724x/gdm_lte.h index 3ecaff1a40cb..bad0855e4721 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); + u8 (*get_endian)(void *priv_dev); }; struct nic { diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c index 996b1f538aae..63921bad519e 100644 --- a/drivers/staging/gdm724x/gdm_mux.c +++ b/drivers/staging/gdm724x/gdm_mux.c @@ -657,7 +657,11 @@ static struct usb_driver gdm_mux_driver = { static int __init gdm_usb_mux_init(void) { - register_lte_tty_driver(); + int ret; + + ret = register_lte_tty_driver(); + if (ret) + return ret; return usb_register(&gdm_mux_driver); } diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c index fc7682c18f20..3cdebb81ba63 100644 --- a/drivers/staging/gdm724x/gdm_tty.c +++ b/drivers/staging/gdm724x/gdm_tty.c @@ -37,13 +37,6 @@ #define MUX_TX_MAX_SIZE 2048 -#define gdm_tty_send(n, d, l, i, c, b) (\ - n->tty_dev->send_func(n->tty_dev->priv_dev, d, l, i, c, b)) -#define gdm_tty_recv(n, c) (\ - n->tty_dev->recv_func(n->tty_dev->priv_dev, c)) -#define gdm_tty_send_control(n, r, v, d, l) (\ - n->tty_dev->send_control(n->tty_dev->priv_dev, r, v, d, l)) - #define GDM_TTY_READY(gdm) (gdm && gdm->tty_dev && gdm->port.count) static struct tty_driver *gdm_driver[TTY_MAX_COUNT]; @@ -146,7 +139,8 @@ static int gdm_tty_recv_complete(void *data, if (!GDM_TTY_READY(gdm)) { if (complete == RECV_PACKET_PROCESS_COMPLETE) - gdm_tty_recv(gdm, gdm_tty_recv_complete); + gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev, + gdm_tty_recv_complete); return TO_HOST_PORT_CLOSE; } @@ -160,7 +154,8 @@ static int gdm_tty_recv_complete(void *data, } if (complete == RECV_PACKET_PROCESS_COMPLETE) - gdm_tty_recv(gdm, gdm_tty_recv_complete); + gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev, + gdm_tty_recv_complete); return 0; } @@ -191,13 +186,12 @@ static int gdm_tty_write(struct tty_struct *tty, const unsigned char *buf, while (1) { sending_len = min(MUX_TX_MAX_SIZE, remain); - gdm_tty_send(gdm, - (void *)(buf + sent_len), - sending_len, - gdm->index, - gdm_tty_send_complete, - gdm - ); + gdm->tty_dev->send_func(gdm->tty_dev->priv_dev, + (void *)(buf + sent_len), + sending_len, + gdm->index, + gdm_tty_send_complete, + gdm); sent_len += sending_len; remain -= sending_len; if (remain <= 0) @@ -256,7 +250,8 @@ int register_lte_tty_device(struct tty_dev *tty_dev, struct device *device) } for (i = 0; i < MAX_ISSUE_NUM; i++) - gdm_tty_recv(gdm, gdm_tty_recv_complete); + gdm->tty_dev->recv_func(gdm->tty_dev->priv_dev, + gdm_tty_recv_complete); return 0; } diff --git a/drivers/staging/gdm724x/gdm_usb.c b/drivers/staging/gdm724x/gdm_usb.c index 87cd1f827455..c95bad4a8615 100644 --- a/drivers/staging/gdm724x/gdm_usb.c +++ b/drivers/staging/gdm724x/gdm_usb.c @@ -72,8 +72,8 @@ static int request_mac_address(struct lte_udev *udev) int actual; int ret = -1; - hci->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_GET_INFORMATION); - hci->len = gdm_cpu_to_dev16(&udev->gdm_ed, 1); + hci->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_GET_INFORMATION); + hci->len = gdm_cpu_to_dev16(udev->gdm_ed, 1); hci->data[0] = MAC_ADDRESS; ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 2), buf, 5, @@ -410,7 +410,7 @@ static void do_rx(struct work_struct *work) phy_dev = r->cb_data; udev = phy_dev->priv_dev; hci = (struct hci_packet *)r->buf; - cmd_evt = gdm_dev16_to_cpu(&udev->gdm_ed, hci->cmd_evt); + cmd_evt = gdm_dev16_to_cpu(udev->gdm_ed, hci->cmd_evt); switch (cmd_evt) { case LTE_GET_INFORMATION_RESULT: @@ -604,7 +604,7 @@ static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf) u16 num_packet = 0; unsigned long flags; - multi_sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_MULTI_SDU); + multi_sdu->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_TX_MULTI_SDU); while (num_packet < MAX_PACKET_IN_MULTI_SDU) { spin_lock_irqsave(&tx->lock, flags); @@ -635,8 +635,8 @@ static u32 packet_aggregation(struct lte_udev *udev, u8 *send_buf) spin_unlock_irqrestore(&tx->lock, flags); } - multi_sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len); - multi_sdu->num_packet = gdm_cpu_to_dev16(&udev->gdm_ed, num_packet); + multi_sdu->len = gdm_cpu_to_dev16(udev->gdm_ed, send_len); + multi_sdu->num_packet = gdm_cpu_to_dev16(udev->gdm_ed, num_packet); return send_len + offsetof(struct multi_sdu, data); } @@ -735,7 +735,7 @@ static int gdm_usb_sdu_send(void *priv_dev, void *data, int len, } sdu = (struct sdu *)t_sdu->buf; - sdu->cmd_evt = gdm_cpu_to_dev16(&udev->gdm_ed, LTE_TX_SDU); + sdu->cmd_evt = gdm_cpu_to_dev16(udev->gdm_ed, LTE_TX_SDU); if (nic_type == NIC_TYPE_ARP) { send_len = len + SDU_PARAM_LEN; memcpy(sdu->data, data, len); @@ -745,10 +745,10 @@ static int gdm_usb_sdu_send(void *priv_dev, void *data, int len, memcpy(sdu->data, data + ETH_HLEN, len - ETH_HLEN); } - sdu->len = gdm_cpu_to_dev16(&udev->gdm_ed, send_len); - sdu->dft_eps_ID = gdm_cpu_to_dev32(&udev->gdm_ed, dft_eps_ID); - sdu->bearer_ID = gdm_cpu_to_dev32(&udev->gdm_ed, eps_ID); - sdu->nic_type = gdm_cpu_to_dev32(&udev->gdm_ed, nic_type); + sdu->len = gdm_cpu_to_dev16(udev->gdm_ed, send_len); + sdu->dft_eps_ID = gdm_cpu_to_dev32(udev->gdm_ed, dft_eps_ID); + sdu->bearer_ID = gdm_cpu_to_dev32(udev->gdm_ed, eps_ID); + sdu->nic_type = gdm_cpu_to_dev32(udev->gdm_ed, nic_type); t_sdu->len = send_len + HCI_HEADER_SIZE; t_sdu->callback = cb; @@ -799,11 +799,11 @@ static int gdm_usb_hci_send(void *priv_dev, void *data, int len, return 0; } -static struct gdm_endian *gdm_usb_get_endian(void *priv_dev) +static u8 gdm_usb_get_endian(void *priv_dev) { struct lte_udev *udev = priv_dev; - return &udev->gdm_ed; + return udev->gdm_ed; } static int gdm_usb_probe(struct usb_interface *intf, @@ -859,9 +859,9 @@ static int gdm_usb_probe(struct usb_interface *intf, * defaults to little endian */ if (idProduct == PID_GDM7243) - gdm_set_endian(&udev->gdm_ed, ENDIANNESS_BIG); + udev->gdm_ed = ENDIANNESS_BIG; else - gdm_set_endian(&udev->gdm_ed, ENDIANNESS_LITTLE); + udev->gdm_ed = ENDIANNESS_LITTLE; ret = request_mac_address(udev); if (ret < 0) { diff --git a/drivers/staging/gdm724x/gdm_usb.h b/drivers/staging/gdm724x/gdm_usb.h index ffb3d995097d..701038685e23 100644 --- a/drivers/staging/gdm724x/gdm_usb.h +++ b/drivers/staging/gdm724x/gdm_usb.h @@ -93,11 +93,11 @@ struct rx_cxt { struct lte_udev { struct usb_device *usbdev; - struct gdm_endian gdm_ed; struct tx_cxt tx; struct rx_cxt rx; struct delayed_work work_tx; struct delayed_work work_rx; + u8 gdm_ed; u8 send_complete; u8 tx_stop; struct usb_interface *intf; diff --git a/drivers/staging/iio/accel/adis16201.c b/drivers/staging/iio/accel/adis16201.c index 2ebd27536216..0fae8aaf1cf4 100644 --- a/drivers/staging/iio/accel/adis16201.c +++ b/drivers/staging/iio/accel/adis16201.c @@ -7,13 +7,13 @@ */ #include <linux/delay.h> -#include <linux/mutex.h> #include <linux/device.h> #include <linux/kernel.h> -#include <linux/spi/spi.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/slab.h> +#include <linux/spi/spi.h> #include <linux/sysfs.h> -#include <linux/module.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -232,6 +232,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, *val = val16; return IIO_VAL_INT; } + return -EINVAL; } @@ -262,6 +263,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, addr = adis16201_addresses[chan->scan_index]; return adis_write_reg_16(st, addr, val16); } + return -EINVAL; } @@ -336,6 +338,7 @@ static int adis16201_probe(struct spi_device *spi) ret = adis_init(st, indio_dev, spi, &adis16201_data); if (ret) return ret; + ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); if (ret) return ret; @@ -348,6 +351,7 @@ static int adis16201_probe(struct spi_device *spi) ret = iio_device_register(indio_dev); if (ret < 0) goto error_cleanup_buffer_trigger; + return 0; error_cleanup_buffer_trigger: diff --git a/drivers/staging/iio/accel/adis16209.c b/drivers/staging/iio/accel/adis16209.c index 7fcef9a2590a..72a18cfe81ee 100644 --- a/drivers/staging/iio/accel/adis16209.c +++ b/drivers/staging/iio/accel/adis16209.c @@ -9,147 +9,82 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> #include <linux/spi/spi.h> #include <linux/slab.h> #include <linux/sysfs.h> -#include <linux/list.h> -#include <linux/module.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> #include <linux/iio/imu/adis.h> -#define ADIS16209_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16209_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16209_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16209_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16209_YACCL_OUT 0x06 +#define ADIS16209_STARTUP_DELAY_MS 220 +#define ADIS16209_FLASH_CNT_REG 0x00 +/* Data Output Register Definitions */ +#define ADIS16209_SUPPLY_OUT_REG 0x02 +#define ADIS16209_XACCL_OUT_REG 0x04 +#define ADIS16209_YACCL_OUT_REG 0x06 /* Output, auxiliary ADC input */ -#define ADIS16209_AUX_ADC 0x08 - +#define ADIS16209_AUX_ADC_REG 0x08 /* Output, temperature */ -#define ADIS16209_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16209_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16209_YINCL_OUT 0x0E - +#define ADIS16209_TEMP_OUT_REG 0x0A +/* Output, +/- 90 degrees X-axis inclination */ +#define ADIS16209_XINCL_OUT_REG 0x0C +#define ADIS16209_YINCL_OUT_REG 0x0E /* Output, +/-180 vertical rotational position */ -#define ADIS16209_ROT_OUT 0x10 - -/* Calibration, x-axis acceleration offset null */ -#define ADIS16209_XACCL_NULL 0x12 - -/* Calibration, y-axis acceleration offset null */ -#define ADIS16209_YACCL_NULL 0x14 - -/* Calibration, x-axis inclination offset null */ -#define ADIS16209_XINCL_NULL 0x16 - -/* Calibration, y-axis inclination offset null */ -#define ADIS16209_YINCL_NULL 0x18 - -/* Calibration, vertical rotation offset null */ -#define ADIS16209_ROT_NULL 0x1A - -/* Alarm 1 amplitude threshold */ -#define ADIS16209_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16209_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16209_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16209_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16209_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16209_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16209_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16209_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16209_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16209_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16209_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16209_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16209_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test at power-on: 1 = disabled, 0 = enabled */ -#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10) - -/* Self-test enable */ -#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2) +#define ADIS16209_ROT_OUT_REG 0x10 +/* + * Calibration Register Definitions. + * Acceleration, inclination or rotation offset null. + */ +#define ADIS16209_XACCL_NULL_REG 0x12 +#define ADIS16209_YACCL_NULL_REG 0x14 +#define ADIS16209_XINCL_NULL_REG 0x16 +#define ADIS16209_YINCL_NULL_REG 0x18 +#define ADIS16209_ROT_NULL_REG 0x1A + +/* Alarm Register Definitions */ +#define ADIS16209_ALM_MAG1_REG 0x20 +#define ADIS16209_ALM_MAG2_REG 0x22 +#define ADIS16209_ALM_SMPL1_REG 0x24 +#define ADIS16209_ALM_SMPL2_REG 0x26 +#define ADIS16209_ALM_CTRL_REG 0x28 + +#define ADIS16209_AUX_DAC_REG 0x30 +#define ADIS16209_GPIO_CTRL_REG 0x32 +#define ADIS16209_SMPL_PRD_REG 0x36 +#define ADIS16209_AVG_CNT_REG 0x38 +#define ADIS16209_SLP_CNT_REG 0x3A + +#define ADIS16209_MSC_CTRL_REG 0x34 +#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST BIT(10) +#define ADIS16209_MSC_CTRL_SELF_TEST_EN BIT(8) +#define ADIS16209_MSC_CTRL_DATA_RDY_EN BIT(2) /* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */ -#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16209_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16209_DIAG_STAT_ALARM1 BIT(8) - -/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */ -#define ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT 5 - -/* SPI communications failure */ -#define ADIS16209_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16209_DIAG_STAT_FLASH_UPT_BIT 2 - +#define ADIS16209_MSC_CTRL_ACTIVE_HIGH BIT(1) +#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 BIT(0) + +#define ADIS16209_STAT_REG 0x3C +#define ADIS16209_STAT_ALARM2 BIT(9) +#define ADIS16209_STAT_ALARM1 BIT(8) +#define ADIS16209_STAT_SELFTEST_FAIL_BIT 5 +#define ADIS16209_STAT_SPI_FAIL_BIT 3 +#define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2 /* Power supply above 3.625 V */ -#define ADIS16209_DIAG_STAT_POWER_HIGH_BIT 1 - +#define ADIS16209_STAT_POWER_HIGH_BIT 1 /* Power supply below 3.15 V */ -#define ADIS16209_DIAG_STAT_POWER_LOW_BIT 0 +#define ADIS16209_STAT_POWER_LOW_BIT 0 -/* GLOB_CMD */ +#define ADIS16209_CMD_REG 0x3E +#define ADIS16209_CMD_SW_RESET BIT(7) +#define ADIS16209_CMD_CLEAR_STAT BIT(4) +#define ADIS16209_CMD_FACTORY_CAL BIT(1) -#define ADIS16209_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16209_GLOB_CMD_CLEAR_STAT BIT(4) -#define ADIS16209_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16209_ERROR_ACTIVE BIT(14) +#define ADIS16209_ERROR_ACTIVE BIT(14) enum adis16209_scan { ADIS16209_SCAN_SUPPLY, @@ -165,10 +100,10 @@ enum adis16209_scan { static const u8 adis16209_addresses[8][1] = { [ADIS16209_SCAN_SUPPLY] = { }, [ADIS16209_SCAN_AUX_ADC] = { }, - [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL }, - [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL }, - [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL }, - [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL }, + [ADIS16209_SCAN_ACC_X] = { ADIS16209_XACCL_NULL_REG }, + [ADIS16209_SCAN_ACC_Y] = { ADIS16209_YACCL_NULL_REG }, + [ADIS16209_SCAN_INCLI_X] = { ADIS16209_XINCL_NULL_REG }, + [ADIS16209_SCAN_INCLI_Y] = { ADIS16209_YINCL_NULL_REG }, [ADIS16209_SCAN_ROT] = { }, [ADIS16209_SCAN_TEMP] = { }, }; @@ -220,30 +155,50 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_VOLTAGE: *val = 0; - if (chan->channel == 0) + switch (chan->channel) { + case 0: *val2 = 305180; /* 0.30518 mV */ - else + break; + case 1: *val2 = 610500; /* 0.6105 mV */ + break; + default: + return -EINVAL; + } return IIO_VAL_INT_PLUS_MICRO; case IIO_TEMP: - *val = -470; /* -0.47 C */ + *val = -470; *val2 = 0; return IIO_VAL_INT_PLUS_MICRO; case IIO_ACCEL: + /* + * IIO base unit for sensitivity of accelerometer + * is milli g. + * 1 LSB represents 0.244 mg. + */ *val = 0; - *val2 = IIO_G_TO_M_S_2(244140); /* 0.244140 mg */ + *val2 = IIO_G_TO_M_S_2(244140); return IIO_VAL_INT_PLUS_NANO; case IIO_INCLI: case IIO_ROT: + /* + * IIO base units for rotation are degrees. + * 1 LSB represents 0.025 milli degrees. + */ *val = 0; - *val2 = 25000; /* 0.025 degree */ + *val2 = 25000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } break; case IIO_CHAN_INFO_OFFSET: - *val = 25000 / -470 - 0x4FE; /* 25 C = 0x4FE */ + /* + * The raw ADC value is 0x4FE when the temperature + * is 25 degrees and the scale factor per milli + * degree celcius is -470. + */ + *val = 25000 / -470 - 0x4FE; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { @@ -257,27 +212,27 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, ret = adis_read_reg_16(st, addr, &val16); if (ret) return ret; - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; + + *val = sign_extend32(val16, bits - 1); return IIO_VAL_INT; } return -EINVAL; } static const struct iio_chan_spec adis16209_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT, ADIS16209_SCAN_SUPPLY, 0, 14), - ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT, ADIS16209_SCAN_TEMP, 0, 12), - ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT, ADIS16209_SCAN_ACC_X, + ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT_REG, ADIS16209_SCAN_SUPPLY, + 0, 14), + ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT_REG, ADIS16209_SCAN_TEMP, 0, 12), + ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT_REG, ADIS16209_SCAN_ACC_X, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT, ADIS16209_SCAN_ACC_Y, + ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT_REG, ADIS16209_SCAN_ACC_Y, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC, ADIS16209_SCAN_AUX_ADC, 0, 12), - ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT, ADIS16209_SCAN_INCLI_X, + ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC_REG, ADIS16209_SCAN_AUX_ADC, 0, 12), + ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT_REG, ADIS16209_SCAN_INCLI_X, 0, 0, 14), - ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT, ADIS16209_SCAN_INCLI_Y, + ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT_REG, ADIS16209_SCAN_INCLI_Y, 0, 0, 14), - ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT, ADIS16209_SCAN_ROT, 0, 0, 14), + ADIS_ROT_CHAN(X, ADIS16209_ROT_OUT_REG, ADIS16209_SCAN_ROT, 0, 0, 14), IIO_CHAN_SOFT_TIMESTAMP(8) }; @@ -288,29 +243,29 @@ static const struct iio_info adis16209_info = { }; static const char * const adis16209_status_error_msgs[] = { - [ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure", - [ADIS16209_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", - [ADIS16209_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", - [ADIS16209_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", - [ADIS16209_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", + [ADIS16209_STAT_SELFTEST_FAIL_BIT] = "Self test failure", + [ADIS16209_STAT_SPI_FAIL_BIT] = "SPI failure", + [ADIS16209_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed", + [ADIS16209_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", + [ADIS16209_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", }; static const struct adis_data adis16209_data = { .read_delay = 30, - .msc_ctrl_reg = ADIS16209_MSC_CTRL, - .glob_cmd_reg = ADIS16209_GLOB_CMD, - .diag_stat_reg = ADIS16209_DIAG_STAT, + .msc_ctrl_reg = ADIS16209_MSC_CTRL_REG, + .glob_cmd_reg = ADIS16209_CMD_REG, + .diag_stat_reg = ADIS16209_STAT_REG, .self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN, .self_test_no_autoclear = true, - .startup_delay = ADIS16209_STARTUP_DELAY, + .startup_delay = ADIS16209_STARTUP_DELAY_MS, .status_error_msgs = adis16209_status_error_msgs, - .status_error_mask = BIT(ADIS16209_DIAG_STAT_SELFTEST_FAIL_BIT) | - BIT(ADIS16209_DIAG_STAT_SPI_FAIL_BIT) | - BIT(ADIS16209_DIAG_STAT_FLASH_UPT_BIT) | - BIT(ADIS16209_DIAG_STAT_POWER_HIGH_BIT) | - BIT(ADIS16209_DIAG_STAT_POWER_LOW_BIT), + .status_error_mask = BIT(ADIS16209_STAT_SELFTEST_FAIL_BIT) | + BIT(ADIS16209_STAT_SPI_FAIL_BIT) | + BIT(ADIS16209_STAT_FLASH_UPT_FAIL_BIT) | + BIT(ADIS16209_STAT_POWER_HIGH_BIT) | + BIT(ADIS16209_STAT_POWER_LOW_BIT), }; static int adis16209_probe(struct spi_device *spi) @@ -319,12 +274,10 @@ static int adis16209_probe(struct spi_device *spi) struct adis *st; struct iio_dev *indio_dev; - /* setup the industrialio driver allocated elements */ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); indio_dev->name = spi->dev.driver->name; @@ -341,7 +294,6 @@ static int adis16209_probe(struct spi_device *spi) if (ret) return ret; - /* Get the device into a sane initial state */ ret = adis_initial_startup(st); if (ret) goto error_cleanup_buffer_trigger; diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 425e8b82533b..df0499fc4802 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -301,8 +301,12 @@ static int ad7192_setup(struct ad7192_state *st, if (pdata->unipolar_en) st->conf |= AD7192_CONF_UNIPOLAR; - if (pdata->burnout_curr_en) + if (pdata->burnout_curr_en && pdata->buf_en && !pdata->chop_en) { st->conf |= AD7192_CONF_BURN; + } else if (pdata->burnout_curr_en) { + dev_warn(&st->sd.spi->dev, + "Can't enable burnout currents: see CHOP or buffer\n"); + } ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); if (ret) diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index bfe180a475ee..bf76a8620bdb 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -254,7 +254,7 @@ static const struct attribute_group ad7816_attribute_group = { static irqreturn_t ad7816_event_handler(int irq, void *private) { iio_push_event(private, IIO_EVENT_CODE_AD7816_OTI, - iio_get_time_ns((struct iio_dev *)private)); + iio_get_time_ns(private)); return IRQ_HANDLED; } diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 2d33632c00e8..3f22d1088713 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -2079,9 +2079,8 @@ static int adt7316_enable(struct device *dev) return _adt7316_store_enabled(chip, 1); } - -SIMPLE_DEV_PM_OPS(adt7316_pm_ops, adt7316_disable, adt7316_enable); EXPORT_SYMBOL_GPL(adt7316_pm_ops); +SIMPLE_DEV_PM_OPS(adt7316_pm_ops, adt7316_disable, adt7316_enable); #endif static const struct iio_info adt7316_info = { diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index 2fe916c48848..d16084d7068c 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -124,8 +124,9 @@ static int ad7150_read_raw(struct iio_dev *indio_dev, } static int ad7150_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, enum iio_event_type type, - enum iio_event_direction dir) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { int ret; u8 threshtype; diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index 19dc896603a1..25f51db05d2d 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -426,8 +426,8 @@ out: } static int ad7152_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) + struct iio_chan_spec const *chan, + long mask) { switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -493,7 +493,7 @@ static const struct iio_chan_spec ad7152_channels[] = { */ static int ad7152_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { int ret = 0; struct ad7152_chip_info *chip; diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index c4a864725376..4882dbc81c53 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -217,7 +217,7 @@ static const unsigned char ad7746_cap_filter_rate_table[][2] = { }; static int ad7746_select_channel(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan) + struct iio_chan_spec const *chan) { struct ad7746_chip_info *chip = iio_priv(indio_dev); int ret, delay, idx; @@ -487,13 +487,13 @@ static int ad7746_write_raw(struct iio_dev *indio_dev, AD7746_CAPDAC_DACP(val) | AD7746_CAPDAC_DACEN : 0; ret = i2c_smbus_write_byte_data(chip->client, - AD7746_REG_CAPDACA, - chip->capdac[chan->channel][0]); + AD7746_REG_CAPDACA, + chip->capdac[chan->channel][0]); if (ret < 0) goto out; ret = i2c_smbus_write_byte_data(chip->client, - AD7746_REG_CAPDACB, - chip->capdac[chan->channel][1]); + AD7746_REG_CAPDACB, + chip->capdac[chan->channel][1]); if (ret < 0) goto out; @@ -675,7 +675,7 @@ static const struct iio_info ad7746_info = { */ static int ad7746_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct ad7746_platform_data *pdata = client->dev.platform_data; struct ad7746_chip_info *chip; diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c index 126e11530ce0..82681300e106 100644 --- a/drivers/staging/iio/light/tsl2x7x.c +++ b/drivers/staging/iio/light/tsl2x7x.c @@ -109,15 +109,15 @@ #define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F /*Prox diode to use */ -#define TSL2X7X_DIODE0 0x10 -#define TSL2X7X_DIODE1 0x20 -#define TSL2X7X_DIODE_BOTH 0x30 +#define TSL2X7X_DIODE0 0x01 +#define TSL2X7X_DIODE1 0x02 +#define TSL2X7X_DIODE_BOTH 0x03 /* LED Power */ #define TSL2X7X_100_mA 0x00 -#define TSL2X7X_50_mA 0x40 -#define TSL2X7X_25_mA 0x80 -#define TSL2X7X_13_mA 0xD0 +#define TSL2X7X_50_mA 0x01 +#define TSL2X7X_25_mA 0x02 +#define TSL2X7X_13_mA 0x03 #define TSL2X7X_MAX_TIMER_CNT 0xFF #define TSL2X7X_MIN_ITIME 3 @@ -228,7 +228,7 @@ static const struct tsl2x7x_settings tsl2x7x_default_settings = { .als_time = 219, /* 101 ms */ .als_gain = 0, .prx_time = 254, /* 5.4 ms */ - .prox_gain = 1, + .prox_gain = 0, .wait_time = 245, .prox_config = 0, .als_gain_trim = 1000, @@ -240,7 +240,9 @@ static const struct tsl2x7x_settings tsl2x7x_default_settings = { .prox_thres_low = 0, .prox_thres_high = 512, .prox_max_samples_cal = 30, - .prox_pulse_count = 8 + .prox_pulse_count = 8, + .prox_diode = TSL2X7X_DIODE1, + .prox_power = TSL2X7X_100_mA }; static const s16 tsl2x7x_als_gain[] = { @@ -279,6 +281,49 @@ static const u8 device_channel_config[] = { ALSPRX2 }; +static int tsl2x7x_clear_interrupts(struct tsl2X7X_chip *chip, int reg) +{ + int ret; + + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | reg); + if (ret < 0) + dev_err(&chip->client->dev, + "%s: failed to clear interrupt status %x: %d\n", + __func__, reg, ret); + + return ret; +} + +static int tsl2x7x_read_status(struct tsl2X7X_chip *chip) +{ + int ret; + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_STATUS); + if (ret < 0) + dev_err(&chip->client->dev, + "%s: failed to read STATUS register: %d\n", __func__, + ret); + + return ret; +} + +static int tsl2x7x_write_control_reg(struct tsl2X7X_chip *chip, u8 data) +{ + int ret; + + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, data); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to write to control register %x: %d\n", + __func__, data, ret); + } + + return ret; +} + /** * tsl2x7x_get_lux() - Reads and calculates current lux value. * @indio_dev: pointer to IIO device @@ -307,8 +352,7 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) u32 ch0lux = 0; u32 ch1lux = 0; - if (mutex_trylock(&chip->als_mutex) == 0) - return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ + mutex_lock(&chip->als_mutex); if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) { /* device is not enabled */ @@ -318,13 +362,10 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) goto out_unlock; } - ret = i2c_smbus_read_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_STATUS); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: Failed to read STATUS Reg\n", __func__); + ret = tsl2x7x_read_status(chip); + if (ret < 0) goto out_unlock; - } + /* is data new & valid */ if (!(ret & TSL2X7X_STA_ADC_VALID)) { dev_err(&chip->client->dev, @@ -346,16 +387,9 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) buf[i] = ret; } - /* clear any existing interrupt status */ - ret = i2c_smbus_write_byte(chip->client, - TSL2X7X_CMD_REG | - TSL2X7X_CMD_SPL_FN | - TSL2X7X_CMD_ALS_INT_CLR); - if (ret < 0) { - dev_err(&chip->client->dev, - "i2c_write_command failed - err = %d\n", ret); - goto out_unlock; /* have no data, so return failure */ - } + ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_ALS_INT_CLR); + if (ret < 0) + goto out_unlock; /* extract ALS/lux data */ ch0 = le16_to_cpup((const __le16 *)&buf[0]); @@ -445,18 +479,11 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) u8 chdata[2]; struct tsl2X7X_chip *chip = iio_priv(indio_dev); - if (mutex_trylock(&chip->prox_mutex) == 0) { - dev_err(&chip->client->dev, - "%s: Can't get prox mutex\n", __func__); - return -EBUSY; - } + mutex_lock(&chip->prox_mutex); - ret = i2c_smbus_read_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_STATUS); - if (ret < 0) { - dev_err(&chip->client->dev, "i2c err=%d\n", ret); + ret = tsl2x7x_read_status(chip); + if (ret < 0) goto prox_poll_err; - } switch (chip->id) { case tsl2571: @@ -464,16 +491,20 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) case tmd2671: case tsl2771: case tmd2771: - if (!(ret & TSL2X7X_STA_ADC_VALID)) + if (!(ret & TSL2X7X_STA_ADC_VALID)) { + ret = -EINVAL; goto prox_poll_err; + } break; case tsl2572: case tsl2672: case tmd2672: case tsl2772: case tmd2772: - if (!(ret & TSL2X7X_STA_PRX_VALID)) + if (!(ret & TSL2X7X_STA_PRX_VALID)) { + ret = -EINVAL; goto prox_poll_err; + } break; } @@ -487,14 +518,13 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) chdata[i] = ret; } - chip->prox_data = - le16_to_cpup((const __le16 *)&chdata[0]); + chip->prox_data = le16_to_cpup((const __le16 *)&chdata[0]); + ret = chip->prox_data; prox_poll_err: - mutex_unlock(&chip->prox_mutex); - return chip->prox_data; + return ret; } /** @@ -582,15 +612,11 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) int i; int ret = 0; u8 *dev_reg; - u8 utmp; int als_count; int als_time; struct tsl2X7X_chip *chip = iio_priv(indio_dev); u8 reg_val = 0; - if (chip->pdata && chip->pdata->power_on) - chip->pdata->power_on(indio_dev); - /* Non calculated parameters */ chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prx_time; chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = chip->settings.wait_time; @@ -635,9 +661,10 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) /* Set the gain based on tsl2x7x_settings struct */ chip->tsl2x7x_config[TSL2X7X_GAIN] = - chip->settings.als_gain | - (TSL2X7X_100_mA | TSL2X7X_DIODE1) | - (chip->settings.prox_gain << 2); + (chip->settings.als_gain & 0xFF) | + ((chip->settings.prox_gain & 0xFF) << 2) | + (chip->settings.prox_diode << 4) | + (chip->settings.prox_power << 6); /* set chip struct re scaling and saturation */ chip->als_saturation = als_count * 922; /* 90% of full scale */ @@ -647,14 +674,9 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) * TSL2X7X Specific power-on / adc enable sequence * Power on the device 1st. */ - utmp = TSL2X7X_CNTL_PWR_ON; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed on CNTRL reg.\n", __func__); + ret = tsl2x7x_write_control_reg(chip, TSL2X7X_CNTL_PWR_ON); + if (ret < 0) return ret; - } /* * Use the following shadow copy for our delay before enabling ADC. @@ -679,16 +701,12 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) * NOW enable the ADC * initialize the desired mode of operation */ - utmp = TSL2X7X_CNTL_PWR_ON | - TSL2X7X_CNTL_ADC_ENBL | - TSL2X7X_CNTL_PROX_DET_ENBL; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed on 2nd CTRL reg.\n", __func__); + ret = tsl2x7x_write_control_reg(chip, + TSL2X7X_CNTL_PWR_ON | + TSL2X7X_CNTL_ADC_ENBL | + TSL2X7X_CNTL_PROX_DET_ENBL); + if (ret < 0) return ret; - } chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; @@ -701,25 +719,14 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL; reg_val |= chip->settings.interrupts_en; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CNTRL, - reg_val); + ret = tsl2x7x_write_control_reg(chip, reg_val); if (ret < 0) - dev_err(&chip->client->dev, - "%s: failed in tsl2x7x_IOCTL_INT_SET.\n", - __func__); + return ret; - /* Clear out any initial interrupts */ - ret = i2c_smbus_write_byte(chip->client, - TSL2X7X_CMD_REG | - TSL2X7X_CMD_SPL_FN | - TSL2X7X_CMD_PROXALS_INT_CLR); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: Failed to clear Int status\n", - __func__); - return ret; - } + ret = tsl2x7x_clear_interrupts(chip, + TSL2X7X_CMD_PROXALS_INT_CLR); + if (ret < 0) + return ret; } return ret; @@ -727,19 +734,11 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) static int tsl2x7x_chip_off(struct iio_dev *indio_dev) { - int ret; struct tsl2X7X_chip *chip = iio_priv(indio_dev); /* turn device off */ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; - - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00); - - if (chip->pdata && chip->pdata->power_off) - chip->pdata->power_off(chip->client); - - return ret; + return tsl2x7x_write_control_reg(chip, 0x00); } /** @@ -777,7 +776,7 @@ unlock: } static void tsl2x7x_prox_calculate(int *data, int length, - struct tsl2x7x_prox_stat *statP) + struct tsl2x7x_prox_stat *stat) { int i; int sample_sum; @@ -787,21 +786,21 @@ static void tsl2x7x_prox_calculate(int *data, int length, length = 1; sample_sum = 0; - statP->min = INT_MAX; - statP->max = INT_MIN; + stat->min = INT_MAX; + stat->max = INT_MIN; for (i = 0; i < length; i++) { sample_sum += data[i]; - statP->min = min(statP->min, data[i]); - statP->max = max(statP->max, data[i]); + stat->min = min(stat->min, data[i]); + stat->max = max(stat->max, data[i]); } - statP->mean = sample_sum / length; + stat->mean = sample_sum / length; sample_sum = 0; for (i = 0; i < length; i++) { - tmp = data[i] - statP->mean; + tmp = data[i] - stat->mean; sample_sum += tmp * tmp; } - statP->stddev = int_sqrt((long)sample_sum / length); + stat->stddev = int_sqrt((long)sample_sum / length); } /** @@ -811,12 +810,12 @@ static void tsl2x7x_prox_calculate(int *data, int length, * Calculates a standard deviation based on the samples, * and sets the threshold accordingly. */ -static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) +static int tsl2x7x_prox_cal(struct iio_dev *indio_dev) { int prox_history[MAX_SAMPLES_CAL + 1]; - int i; + int i, ret; struct tsl2x7x_prox_stat prox_stat_data[2]; - struct tsl2x7x_prox_stat *calP; + struct tsl2x7x_prox_stat *cal; struct tsl2X7X_chip *chip = iio_priv(indio_dev); u8 tmp_irq_settings; u8 current_state = chip->tsl2x7x_chip_status; @@ -829,40 +828,53 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) } /* have to stop to change settings */ - tsl2x7x_chip_off(indio_dev); + ret = tsl2x7x_chip_off(indio_dev); + if (ret < 0) + return ret; /* Enable proximity detection save just in case prox not wanted yet*/ tmp_irq_settings = chip->settings.interrupts_en; chip->settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL; /*turn on device if not already on*/ - tsl2x7x_chip_on(indio_dev); + ret = tsl2x7x_chip_on(indio_dev); + if (ret < 0) + return ret; /*gather the samples*/ for (i = 0; i < chip->settings.prox_max_samples_cal; i++) { usleep_range(15000, 17500); - tsl2x7x_get_prox(indio_dev); + ret = tsl2x7x_get_prox(indio_dev); + if (ret < 0) + return ret; prox_history[i] = chip->prox_data; dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", i, chip->prox_data); } - tsl2x7x_chip_off(indio_dev); - calP = &prox_stat_data[PROX_STAT_CAL]; + ret = tsl2x7x_chip_off(indio_dev); + if (ret < 0) + return ret; + cal = &prox_stat_data[PROX_STAT_CAL]; tsl2x7x_prox_calculate(prox_history, - chip->settings.prox_max_samples_cal, calP); - chip->settings.prox_thres_high = (calP->max << 1) - calP->mean; + chip->settings.prox_max_samples_cal, cal); + chip->settings.prox_thres_high = (cal->max << 1) - cal->mean; dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n", - calP->min, calP->mean, calP->max); + cal->min, cal->mean, cal->max); dev_info(&chip->client->dev, "%s proximity threshold set to %d\n", chip->client->name, chip->settings.prox_thres_high); /* back to the way they were */ chip->settings.interrupts_en = tmp_irq_settings; - if (current_state == TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_on(indio_dev); + if (current_state == TSL2X7X_CHIP_WORKING) { + ret = tsl2x7x_chip_on(indio_dev); + if (ret < 0) + return ret; + } + + return 0; } static ssize_t @@ -931,8 +943,11 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev, if (strtobool(buf, &value)) return -EINVAL; - if (value) - tsl2x7x_als_calibrate(indio_dev); + if (value) { + ret = tsl2x7x_als_calibrate(indio_dev); + if (ret < 0) + return ret; + } ret = tsl2x7x_invoke_change(indio_dev); if (ret < 0) @@ -997,8 +1012,11 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev, return -EINVAL; } - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_off(indio_dev); + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { + ret = tsl2x7x_chip_off(indio_dev); + if (ret < 0) + return ret; + } /* Zero out the table */ memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux)); @@ -1022,8 +1040,11 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev, if (strtobool(buf, &value)) return -EINVAL; - if (value) - tsl2x7x_prox_cal(indio_dev); + if (value) { + ret = tsl2x7x_prox_cal(indio_dev); + if (ret < 0) + return ret; + } ret = tsl2x7x_invoke_change(indio_dev); if (ret < 0) @@ -1402,13 +1423,13 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) struct tsl2X7X_chip *chip = iio_priv(indio_dev); s64 timestamp = iio_get_time_ns(indio_dev); int ret; - u8 value; - value = i2c_smbus_read_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_STATUS); + ret = tsl2x7x_read_status(chip); + if (ret < 0) + return ret; /* What type of interrupt do we need to process */ - if (value & TSL2X7X_STA_PRX_INTR) { + if (ret & TSL2X7X_STA_PRX_INTR) { tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */ iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, @@ -1418,7 +1439,7 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) timestamp); } - if (value & TSL2X7X_STA_ALS_INTR) { + if (ret & TSL2X7X_STA_ALS_INTR) { tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */ iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT, @@ -1427,14 +1448,10 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) IIO_EV_DIR_EITHER), timestamp); } - /* Clear interrupt now that we have handled it. */ - ret = i2c_smbus_write_byte(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | - TSL2X7X_CMD_PROXALS_INT_CLR); + + ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_PROXALS_INT_CLR); if (ret < 0) - dev_err(&chip->client->dev, - "Failed to clear irq from event handler. err = %d\n", - ret); + return ret; return IRQ_HANDLED; } @@ -1461,7 +1478,6 @@ static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = { &dev_attr_in_illuminance0_target_input.attr, &dev_attr_in_illuminance0_calibrate.attr, &dev_attr_in_illuminance0_lux_table.attr, - &iio_const_attr_in_proximity0_calibscale_available.dev_attr.attr, NULL }; @@ -1792,12 +1808,6 @@ static int tsl2x7x_suspend(struct device *dev) chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; } - if (chip->pdata && chip->pdata->platform_power) { - pm_message_t pmm = {PM_EVENT_SUSPEND}; - - chip->pdata->platform_power(dev, pmm); - } - return ret; } @@ -1807,12 +1817,6 @@ static int tsl2x7x_resume(struct device *dev) struct tsl2X7X_chip *chip = iio_priv(indio_dev); int ret = 0; - if (chip->pdata && chip->pdata->platform_power) { - pm_message_t pmm = {PM_EVENT_RESUME}; - - chip->pdata->platform_power(dev, pmm); - } - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED) ret = tsl2x7x_chip_on(indio_dev); diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h index df00f2ec1719..28b0e7fdc9b8 100644 --- a/drivers/staging/iio/light/tsl2x7x.h +++ b/drivers/staging/iio/light/tsl2x7x.h @@ -21,7 +21,6 @@ #ifndef __TSL2X7X_H #define __TSL2X7X_H -#include <linux/pm.h> struct tsl2x7x_lux { unsigned int ratio; @@ -79,6 +78,8 @@ struct tsl2x7x_settings { int prox_thres_high; int prox_pulse_count; int prox_max_samples_cal; + int prox_diode; + int prox_power; }; /** @@ -91,9 +92,6 @@ struct tsl2x7x_settings { * */ struct tsl2X7X_platform_data { - int (*platform_power)(struct device *dev, pm_message_t); - int (*power_on)(struct iio_dev *indio_dev); - int (*power_off)(struct i2c_client *dev); struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE]; struct tsl2x7x_settings *platform_default_settings; }; diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index c44eb577dc35..275e8dfff836 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -388,14 +388,16 @@ static IIO_DEV_ATTR_VPERIOD(0444, ade7753_read_16bit, NULL, ADE7753_PERIOD); -static IIO_DEV_ATTR_CH_OFF(1, 0644, - ade7753_read_8bit, - ade7753_write_8bit, - ADE7753_CH1OS); -static IIO_DEV_ATTR_CH_OFF(2, 0644, - ade7753_read_8bit, - ade7753_write_8bit, - ADE7753_CH2OS); + +static IIO_DEVICE_ATTR(choff_1, 0644, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_CH1OS); + +static IIO_DEVICE_ATTR(choff_2, 0644, + ade7753_read_8bit, + ade7753_write_8bit, + ADE7753_CH2OS); static int ade7753_set_irq(struct device *dev, bool enable) { diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index 3a1e342d75fb..9aa067736715 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -132,7 +132,7 @@ static int ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val) } static int ade7754_spi_write_reg_16(struct device *dev, - u8 reg_address, u16 value) + u8 reg_address, u16 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -140,8 +140,8 @@ static int ade7754_spi_write_reg_16(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = ADE7754_WRITE_REG(reg_address); - st->tx[1] = (value >> 8) & 0xFF; - st->tx[2] = value & 0xFF; + st->tx[1] = (val >> 8) & 0xFF; + st->tx[2] = val & 0xFF; ret = spi_write(st->us, st->tx, 3); mutex_unlock(&st->buf_lock); diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h index 6ae78d8aa24f..2de81b53e786 100644 --- a/drivers/staging/iio/meter/ade7758.h +++ b/drivers/staging/iio/meter/ade7758.h @@ -111,7 +111,7 @@ * @trig: data ready trigger registered with iio * @tx: transmit buffer * @rx: receive buffer - * @buf_lock: mutex to protect tx and rx + * @buf_lock: mutex to protect tx, rx, read and write frequency **/ struct ade7758_state { struct spi_device *us; diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 7b7ffe5ed186..4e0dbf5c5705 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -24,17 +24,25 @@ #include "meter.h" #include "ade7758.h" -int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val) +static int __ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val) { - int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); - mutex_lock(&st->buf_lock); st->tx[0] = ADE7758_WRITE_REG(reg_address); st->tx[1] = val; - ret = spi_write(st->us, st->tx, 2); + return spi_write(st->us, st->tx, 2); +} + +int ade7758_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val) +{ + int ret; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ade7758_state *st = iio_priv(indio_dev); + + mutex_lock(&st->buf_lock); + ret = __ade7758_spi_write_reg_8(dev, reg_address, val); mutex_unlock(&st->buf_lock); return ret; @@ -91,7 +99,7 @@ static int ade7758_spi_write_reg_24(struct device *dev, u8 reg_address, return ret; } -int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) +static int __ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7758_state *st = iio_priv(indio_dev); @@ -111,7 +119,6 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) }, }; - mutex_lock(&st->buf_lock); st->tx[0] = ADE7758_READ_REG(reg_address); st->tx[1] = 0; @@ -124,7 +131,19 @@ int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) *val = st->rx[0]; error_ret: + return ret; +} + +int ade7758_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ade7758_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->buf_lock); + ret = __ade7758_spi_read_reg_8(dev, reg_address, val); mutex_unlock(&st->buf_lock); + return ret; } @@ -484,6 +503,8 @@ static int ade7758_write_samp_freq(struct device *dev, int val) { int ret; u8 reg, t; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ade7758_state *st = iio_priv(indio_dev); switch (val) { case 26040: @@ -499,20 +520,23 @@ static int ade7758_write_samp_freq(struct device *dev, int val) t = 3; break; default: - ret = -EINVAL; - goto out; + return -EINVAL; } - ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, ®); + mutex_lock(&st->buf_lock); + + ret = __ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, ®); if (ret) goto out; reg &= ~(5 << 3); reg |= t << 5; - ret = ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg); + ret = __ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg); out: + mutex_unlock(&st->buf_lock); + return ret; } @@ -526,9 +550,9 @@ static int ade7758_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&indio_dev->mlock); + ret = ade7758_read_samp_freq(&indio_dev->dev, val); - mutex_unlock(&indio_dev->mlock); + return ret; default: return -EINVAL; @@ -547,9 +571,9 @@ static int ade7758_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: if (val2) return -EINVAL; - mutex_lock(&indio_dev->mlock); + ret = ade7758_write_samp_freq(&indio_dev->dev, val); - mutex_unlock(&indio_dev->mlock); + return ret; default: return -EINVAL; diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c index 1f0d1a0cf889..4f6b338cffeb 100644 --- a/drivers/staging/iio/meter/ade7758_trigger.c +++ b/drivers/staging/iio/meter/ade7758_trigger.c @@ -30,11 +30,11 @@ static irqreturn_t ade7758_data_rdy_trig_poll(int irq, void *private) * ade7758_data_rdy_trigger_set_state() set datardy interrupt state **/ static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) + bool state) { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); - dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); + dev_dbg(&indio_dev->dev, "(%d)\n", state); return ade7758_set_irq(&indio_dev->dev, state); } @@ -63,8 +63,8 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev) int ret; st->trig = iio_trigger_alloc("%s-dev%d", - spi_get_device_id(st->us)->name, - indio_dev->id); + spi_get_device_id(st->us)->name, + indio_dev->id); if (!st->trig) { ret = -ENOMEM; goto error_ret; diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index d99cf508d8d0..c078b770fa53 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -72,8 +72,8 @@ struct ade7759_state { }; static int ade7759_spi_write_reg_8(struct device *dev, - u8 reg_address, - u8 val) + u8 reg_address, + u8 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -91,8 +91,8 @@ static int ade7759_spi_write_reg_8(struct device *dev, /*Unlocked version of ade7759_spi_write_reg_16 function */ static int __ade7759_spi_write_reg_16(struct device *dev, - u8 reg_address, - u16 value) + u8 reg_address, + u16 value) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); @@ -104,8 +104,8 @@ static int __ade7759_spi_write_reg_16(struct device *dev, } static int ade7759_spi_write_reg_16(struct device *dev, - u8 reg_address, - u16 value) + u8 reg_address, + u16 value) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -119,8 +119,8 @@ static int ade7759_spi_write_reg_16(struct device *dev, } static int ade7759_spi_read_reg_8(struct device *dev, - u8 reg_address, - u8 *val) + u8 reg_address, + u8 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); @@ -128,8 +128,9 @@ static int ade7759_spi_read_reg_8(struct device *dev, ret = spi_w8r8(st->us, ADE7759_READ_REG(reg_address)); if (ret < 0) { - dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", - reg_address); + dev_err(&st->us->dev, + "problem when reading 8 bit register 0x%02X", + reg_address); return ret; } *val = ret; @@ -138,8 +139,8 @@ static int ade7759_spi_read_reg_8(struct device *dev, } static int ade7759_spi_read_reg_16(struct device *dev, - u8 reg_address, - u16 *val) + u8 reg_address, + u16 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); @@ -158,8 +159,8 @@ static int ade7759_spi_read_reg_16(struct device *dev, } static int ade7759_spi_read_reg_40(struct device *dev, - u8 reg_address, - u64 *val) + u8 reg_address, + u64 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); @@ -179,8 +180,9 @@ static int ade7759_spi_read_reg_40(struct device *dev, ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { - dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X", - reg_address); + dev_err(&st->us->dev, + "problem when reading 40 bit register 0x%02X", + reg_address); goto error_ret; } *val = ((u64)st->rx[1] << 32) | ((u64)st->rx[2] << 24) | @@ -192,8 +194,8 @@ error_ret: } static ssize_t ade7759_read_8bit(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u8 val = 0; @@ -207,8 +209,8 @@ static ssize_t ade7759_read_8bit(struct device *dev, } static ssize_t ade7759_read_16bit(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u16 val = 0; @@ -222,8 +224,8 @@ static ssize_t ade7759_read_16bit(struct device *dev, } static ssize_t ade7759_read_40bit(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u64 val = 0; @@ -237,9 +239,9 @@ static ssize_t ade7759_read_40bit(struct device *dev, } static ssize_t ade7759_write_8bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, + size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -255,9 +257,9 @@ error_ret: } static ssize_t ade7759_write_16bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, + size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -277,9 +279,7 @@ static int ade7759_reset(struct device *dev) int ret; u16 val; - ret = ade7759_spi_read_reg_16(dev, - ADE7759_MODE, - &val); + ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val); if (ret < 0) return ret; @@ -328,14 +328,16 @@ static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(0644, ade7759_read_16bit, ade7759_write_16bit, ADE7759_APGAIN); -static IIO_DEV_ATTR_CH_OFF(1, 0644, - ade7759_read_8bit, - ade7759_write_8bit, - ADE7759_CH1OS); -static IIO_DEV_ATTR_CH_OFF(2, 0644, - ade7759_read_8bit, - ade7759_write_8bit, - ADE7759_CH2OS); + +static IIO_DEVICE_ATTR(choff_1, 0644, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_CH1OS); + +static IIO_DEVICE_ATTR(choff_2, 0644, + ade7759_read_8bit, + ade7759_write_8bit, + ADE7759_CH2OS); static int ade7759_set_irq(struct device *dev, bool enable) { @@ -365,9 +367,7 @@ static int ade7759_stop_device(struct device *dev) int ret; u16 val; - ret = ade7759_spi_read_reg_16(dev, - ADE7759_MODE, - &val); + ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val); if (ret < 0) { dev_err(dev, "unable to power down the device, error: %d\n", ret); @@ -404,16 +404,14 @@ err_ret: } static ssize_t ade7759_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u16 t; int sps; - ret = ade7759_spi_read_reg_16(dev, - ADE7759_MODE, - &t); + ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &t); if (ret) return ret; @@ -424,9 +422,9 @@ static ssize_t ade7759_read_frequency(struct device *dev, } static ssize_t ade7759_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, + size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7759_state *st = iio_priv(indio_dev); diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c index 8106f8cceeab..317e4f0d8176 100644 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -17,7 +17,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev, u16 reg_address, - u8 value) + u8 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -26,7 +26,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = (reg_address >> 8) & 0xFF; st->tx[1] = reg_address & 0xFF; - st->tx[2] = value; + st->tx[2] = val; ret = i2c_master_send(st->i2c, st->tx, 3); mutex_unlock(&st->buf_lock); @@ -36,7 +36,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev, static int ade7854_i2c_write_reg_16(struct device *dev, u16 reg_address, - u16 value) + u16 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -45,8 +45,8 @@ static int ade7854_i2c_write_reg_16(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = (reg_address >> 8) & 0xFF; st->tx[1] = reg_address & 0xFF; - st->tx[2] = (value >> 8) & 0xFF; - st->tx[3] = value & 0xFF; + st->tx[2] = (val >> 8) & 0xFF; + st->tx[3] = val & 0xFF; ret = i2c_master_send(st->i2c, st->tx, 4); mutex_unlock(&st->buf_lock); @@ -56,7 +56,7 @@ static int ade7854_i2c_write_reg_16(struct device *dev, static int ade7854_i2c_write_reg_24(struct device *dev, u16 reg_address, - u32 value) + u32 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -65,9 +65,9 @@ static int ade7854_i2c_write_reg_24(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = (reg_address >> 8) & 0xFF; st->tx[1] = reg_address & 0xFF; - st->tx[2] = (value >> 16) & 0xFF; - st->tx[3] = (value >> 8) & 0xFF; - st->tx[4] = value & 0xFF; + st->tx[2] = (val >> 16) & 0xFF; + st->tx[3] = (val >> 8) & 0xFF; + st->tx[4] = val & 0xFF; ret = i2c_master_send(st->i2c, st->tx, 5); mutex_unlock(&st->buf_lock); @@ -77,7 +77,7 @@ static int ade7854_i2c_write_reg_24(struct device *dev, static int ade7854_i2c_write_reg_32(struct device *dev, u16 reg_address, - u32 value) + u32 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -86,10 +86,10 @@ static int ade7854_i2c_write_reg_32(struct device *dev, mutex_lock(&st->buf_lock); st->tx[0] = (reg_address >> 8) & 0xFF; st->tx[1] = reg_address & 0xFF; - st->tx[2] = (value >> 24) & 0xFF; - st->tx[3] = (value >> 16) & 0xFF; - st->tx[4] = (value >> 8) & 0xFF; - st->tx[5] = value & 0xFF; + st->tx[2] = (val >> 24) & 0xFF; + st->tx[3] = (val >> 16) & 0xFF; + st->tx[4] = (val >> 8) & 0xFF; + st->tx[5] = val & 0xFF; ret = i2c_master_send(st->i2c, st->tx, 6); mutex_unlock(&st->buf_lock); diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index 63e200ffd1f2..4419b8f06197 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -16,8 +16,8 @@ #include "ade7854.h" static int ade7854_spi_write_reg_8(struct device *dev, - u16 reg_address, - u8 value) + u16 reg_address, + u8 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -32,7 +32,7 @@ static int ade7854_spi_write_reg_8(struct device *dev, st->tx[0] = ADE7854_WRITE_REG; st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - st->tx[3] = value & 0xFF; + st->tx[3] = val & 0xFF; ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); @@ -41,8 +41,8 @@ static int ade7854_spi_write_reg_8(struct device *dev, } static int ade7854_spi_write_reg_16(struct device *dev, - u16 reg_address, - u16 value) + u16 reg_address, + u16 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -57,8 +57,8 @@ static int ade7854_spi_write_reg_16(struct device *dev, st->tx[0] = ADE7854_WRITE_REG; st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - st->tx[3] = (value >> 8) & 0xFF; - st->tx[4] = value & 0xFF; + st->tx[3] = (val >> 8) & 0xFF; + st->tx[4] = val & 0xFF; ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); @@ -67,8 +67,8 @@ static int ade7854_spi_write_reg_16(struct device *dev, } static int ade7854_spi_write_reg_24(struct device *dev, - u16 reg_address, - u32 value) + u16 reg_address, + u32 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -83,9 +83,9 @@ static int ade7854_spi_write_reg_24(struct device *dev, st->tx[0] = ADE7854_WRITE_REG; st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - st->tx[3] = (value >> 16) & 0xFF; - st->tx[4] = (value >> 8) & 0xFF; - st->tx[5] = value & 0xFF; + st->tx[3] = (val >> 16) & 0xFF; + st->tx[4] = (val >> 8) & 0xFF; + st->tx[5] = val & 0xFF; ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); @@ -94,8 +94,8 @@ static int ade7854_spi_write_reg_24(struct device *dev, } static int ade7854_spi_write_reg_32(struct device *dev, - u16 reg_address, - u32 value) + u16 reg_address, + u32 val) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -110,10 +110,10 @@ static int ade7854_spi_write_reg_32(struct device *dev, st->tx[0] = ADE7854_WRITE_REG; st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - st->tx[3] = (value >> 24) & 0xFF; - st->tx[4] = (value >> 16) & 0xFF; - st->tx[5] = (value >> 8) & 0xFF; - st->tx[6] = value & 0xFF; + st->tx[3] = (val >> 24) & 0xFF; + st->tx[4] = (val >> 16) & 0xFF; + st->tx[5] = (val >> 8) & 0xFF; + st->tx[6] = val & 0xFF; ret = spi_sync_transfer(st->spi, &xfer, 1); mutex_unlock(&st->buf_lock); @@ -122,8 +122,8 @@ static int ade7854_spi_write_reg_32(struct device *dev, } static int ade7854_spi_read_reg_8(struct device *dev, - u16 reg_address, - u8 *val) + u16 reg_address, + u8 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -149,7 +149,7 @@ static int ade7854_spi_read_reg_8(struct device *dev, ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X", - reg_address); + reg_address); goto error_ret; } *val = st->rx[0]; @@ -160,8 +160,8 @@ error_ret: } static int ade7854_spi_read_reg_16(struct device *dev, - u16 reg_address, - u16 *val) + u16 reg_address, + u16 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -186,7 +186,7 @@ static int ade7854_spi_read_reg_16(struct device *dev, ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X", - reg_address); + reg_address); goto error_ret; } *val = be16_to_cpup((const __be16 *)st->rx); @@ -197,8 +197,8 @@ error_ret: } static int ade7854_spi_read_reg_24(struct device *dev, - u16 reg_address, - u32 *val) + u16 reg_address, + u32 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -224,7 +224,7 @@ static int ade7854_spi_read_reg_24(struct device *dev, ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X", - reg_address); + reg_address); goto error_ret; } *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; @@ -235,8 +235,8 @@ error_ret: } static int ade7854_spi_read_reg_32(struct device *dev, - u16 reg_address, - u32 *val) + u16 reg_address, + u32 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -262,7 +262,7 @@ static int ade7854_spi_read_reg_32(struct device *dev, ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X", - reg_address); + reg_address); goto error_ret; } *val = be32_to_cpup((const __be32 *)st->rx); diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h index c27247a7891a..a82d38224cbd 100644 --- a/drivers/staging/iio/meter/ade7854.h +++ b/drivers/staging/iio/meter/ade7854.h @@ -152,20 +152,20 @@ * @rx: receive buffer **/ struct ade7854_state { - struct spi_device *spi; - struct i2c_client *i2c; - int (*read_reg_8)(struct device *, u16, u8 *); - int (*read_reg_16)(struct device *, u16, u16 *); - int (*read_reg_24)(struct device *, u16, u32 *); - int (*read_reg_32)(struct device *, u16, u32 *); - int (*write_reg_8)(struct device *, u16, u8); - int (*write_reg_16)(struct device *, u16, u16); - int (*write_reg_24)(struct device *, u16, u32); - int (*write_reg_32)(struct device *, u16, u32); - int irq; - struct mutex buf_lock; - u8 tx[ADE7854_MAX_TX] ____cacheline_aligned; - u8 rx[ADE7854_MAX_RX]; + struct spi_device *spi; + struct i2c_client *i2c; + int (*read_reg_8)(struct device *dev, u16 reg_address, u8 *val); + int (*read_reg_16)(struct device *dev, u16 reg_address, u16 *val); + int (*read_reg_24)(struct device *dev, u16 reg_address, u32 *val); + int (*read_reg_32)(struct device *dev, u16 reg_address, u32 *val); + int (*write_reg_8)(struct device *dev, u16 reg_address, u8 val); + int (*write_reg_16)(struct device *dev, u16 reg_address, u16 val); + int (*write_reg_24)(struct device *dev, u16 reg_address, u32 val); + int (*write_reg_32)(struct device *dev, u16 reg_address, u32 val); + int irq; + struct mutex buf_lock; + u8 tx[ADE7854_MAX_TX] ____cacheline_aligned; + u8 rx[ADE7854_MAX_RX]; }; diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h index edf26302fa57..5ed59bf30a25 100644 --- a/drivers/staging/iio/meter/meter.h +++ b/drivers/staging/iio/meter/meter.h @@ -348,9 +348,6 @@ #define IIO_DEV_ATTR_VPERIOD(_mode, _show, _store, _addr) \ IIO_DEVICE_ATTR(vperiod, _mode, _show, _store, _addr) -#define IIO_DEV_ATTR_CH_OFF(_num, _mode, _show, _store, _addr) \ - IIO_DEVICE_ATTR(choff_##_num, _mode, _show, _store, _addr) - /* active energy register, AENERGY, is more than half full */ #define IIO_EVENT_ATTR_AENERGY_HALF_FULL(_evlist, _show, _store, _mask) \ IIO_EVENT_ATTR_SH(aenergy_half_full, _evlist, _show, _store, _mask) diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index f8baab061eba..ac13b99bd9cb 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -35,8 +35,6 @@ #define AD2S1210_SET_RES1 0x02 #define AD2S1210_SET_RES0 0x01 -#define AD2S1210_SET_ENRESOLUTION (AD2S1210_SET_ENRES1 | \ - AD2S1210_SET_ENRES0) #define AD2S1210_SET_RESOLUTION (AD2S1210_SET_RES1 | AD2S1210_SET_RES0) #define AD2S1210_REG_POSITION 0x80 @@ -53,10 +51,6 @@ #define AD2S1210_REG_SOFT_RESET 0xF0 #define AD2S1210_REG_FAULT 0xFF -/* pin SAMPLE, A0, A1, RES0, RES1, is controlled by driver */ -#define AD2S1210_SAA 3 -#define AD2S1210_PN (AD2S1210_SAA + AD2S1210_RES) - #define AD2S1210_MIN_CLKIN 6144000 #define AD2S1210_MAX_CLKIN 10240000 #define AD2S1210_MIN_EXCIT 2000 @@ -64,10 +58,6 @@ #define AD2S1210_MIN_FCW 0x4 #define AD2S1210_MAX_FCW 0x50 -/* default input clock on serial interface */ -#define AD2S1210_DEF_CLKIN 8192000 -/* clock period in nano second */ -#define AD2S1210_DEF_TCK (1000000000 / AD2S1210_DEF_CLKIN) #define AD2S1210_DEF_EXCIT 10000 enum ad2s1210_mode { @@ -86,7 +76,6 @@ struct ad2s1210_state { unsigned int fclkin; unsigned int fexcit; bool hysteresis; - bool old_data; u8 resolution; enum ad2s1210_mode mode; u8 rx[2] ____cacheline_aligned; @@ -117,7 +106,6 @@ static int ad2s1210_config_write(struct ad2s1210_state *st, u8 data) ret = spi_write(st->sdev, st->tx, 1); if (ret < 0) return ret; - st->old_data = true; return 0; } @@ -139,7 +127,6 @@ static int ad2s1210_config_read(struct ad2s1210_state *st, ret = spi_sync_transfer(st->sdev, &xfer, 1); if (ret < 0) return ret; - st->old_data = true; return st->rx[1]; } @@ -165,9 +152,10 @@ int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st) static unsigned char ad2s1210_read_resolution_pin(struct ad2s1210_state *st) { - return ad2s1210_resolution_value[ - (gpio_get_value(st->pdata->res[0]) << 1) | - gpio_get_value(st->pdata->res[1])]; + int resolution = (gpio_get_value(st->pdata->res[0]) << 1) | + gpio_get_value(st->pdata->res[1]); + + return ad2s1210_resolution_value[resolution]; } static const int ad2s1210_res_pins[4][2] = { diff --git a/drivers/staging/irda/TODO b/drivers/staging/irda/TODO deleted file mode 100644 index 7d98a5cffaff..000000000000 --- a/drivers/staging/irda/TODO +++ /dev/null @@ -1,4 +0,0 @@ -The irda code will be removed soon from the kernel tree as it is old and -obsolete and broken. - -Don't worry about fixing up anything here, it's not needed. diff --git a/drivers/staging/irda/drivers/Kconfig b/drivers/staging/irda/drivers/Kconfig deleted file mode 100644 index e070e1222733..000000000000 --- a/drivers/staging/irda/drivers/Kconfig +++ /dev/null @@ -1,398 +0,0 @@ -menu "Infrared-port device drivers" - depends on IRDA!=n - -comment "SIR device drivers" - -config IRTTY_SIR - tristate "IrTTY (uses Linux serial driver)" - depends on IRDA && TTY - help - Say Y here if you want to build support for the IrTTY line - discipline. To compile it as a module, choose M here: the module - will be called irtty-sir. IrTTY makes it possible to use Linux's - own serial driver for all IrDA ports that are 16550 compatible. - Most IrDA chips are 16550 compatible so you should probably say Y - to this option. Using IrTTY will however limit the speed of the - connection to 115200 bps (IrDA SIR mode). - - If unsure, say Y. - -config BFIN_SIR - tristate "Blackfin SIR on UART" - depends on BLACKFIN && IRDA - default n - help - Say Y here if your want to enable SIR function on Blackfin UART - devices. - - To activate this driver you can start irattach like: - "irattach irda0 -s" - - Saying M, it will be built as a module named bfin_sir. - - Note that you need to turn off one of the serial drivers for SIR - to use that UART. - -config BFIN_SIR0 - bool "Blackfin SIR on UART0" - depends on BFIN_SIR && !SERIAL_BFIN_UART0 - -config BFIN_SIR1 - bool "Blackfin SIR on UART1" - depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561) - -config BFIN_SIR2 - bool "Blackfin SIR on UART2" - depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539) - -config BFIN_SIR3 - bool "Blackfin SIR on UART3" - depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x) - -choice - prompt "SIR Mode" - depends on BFIN_SIR - default SIR_BFIN_DMA - -config SIR_BFIN_DMA - bool "DMA mode" - depends on !DMA_UNCACHED_NONE - -config SIR_BFIN_PIO - bool "PIO mode" -endchoice - -config SH_SIR - tristate "SuperH SIR on UART" - depends on IRDA && SUPERH && \ - (CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \ - CPU_SUBTYPE_SH7724) - default n - help - Say Y here if your want to enable SIR function on SuperH UART - devices. - -comment "Dongle support" - -config DONGLE - bool "Serial dongle support" - depends on IRTTY_SIR - help - Say Y here if you have an infrared device that connects to your - computer's serial port. These devices are called dongles. Then say Y - or M to the driver for your particular dongle below. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about serial dongles. - -config ESI_DONGLE - tristate "ESI JetEye PC dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Extended Systems - JetEye PC dongle. To compile it as a module, choose M here. The ESI - dongle attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for ESI - dongles you will have to start irattach like this: - "irattach -d esi". - -config ACTISYS_DONGLE - tristate "ACTiSYS IR-220L and IR220L+ dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the ACTiSYS IR-220L and - IR220L+ dongles. To compile it as a module, choose M here. The - ACTiSYS dongles attaches to the normal 9-pin serial port connector, - and can currently only be used by IrTTY. To activate support for - ACTiSYS dongles you will have to start irattach like this: - "irattach -d actisys" or "irattach -d actisys+". - -config TEKRAM_DONGLE - tristate "Tekram IrMate 210B dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Tekram IrMate 210B - dongle. To compile it as a module, choose M here. The Tekram dongle - attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for Tekram - dongles you will have to start irattach like this: - "irattach -d tekram". - -config TOIM3232_DONGLE - tristate "TOIM3232 IrDa dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Vishay/Temic - TOIM3232 and TOIM4232 based dongles. - To compile it as a module, choose M here. - -config LITELINK_DONGLE - tristate "Parallax LiteLink dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Parallax Litelink - dongle. To compile it as a module, choose M here. The Parallax - dongle attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for Parallax - dongles you will have to start irattach like this: - "irattach -d litelink". - -config MA600_DONGLE - tristate "Mobile Action MA600 dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Mobile Action MA600 - dongle. To compile it as a module, choose M here. The MA600 dongle - attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. The driver should also support - the MA620 USB version of the dongle, if the integrated USB-to-RS232 - converter is supported by usbserial. To activate support for - MA600 dongle you will have to start irattach like this: - "irattach -d ma600". - -config GIRBIL_DONGLE - tristate "Greenwich GIrBIL dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Greenwich GIrBIL - dongle. If you want to compile it as a module, choose M here. - The Greenwich dongle attaches to the normal 9-pin serial port - connector, and can currently only be used by IrTTY. To activate - support for Greenwich dongles you will have to start irattach - like this: "irattach -d girbil". - -config MCP2120_DONGLE - tristate "Microchip MCP2120" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Microchip MCP2120 - dongle. If you want to compile it as a module, choose M here. - The MCP2120 dongle attaches to the normal 9-pin serial port - connector, and can currently only be used by IrTTY. To activate - support for MCP2120 dongles you will have to start irattach - like this: "irattach -d mcp2120". - - You must build this dongle yourself. For more information see: - <http://www.eyetap.org/~tangf/irda_sir_linux.html> - -config OLD_BELKIN_DONGLE - tristate "Old Belkin dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Adaptec Airport 1000 - and 2000 dongles. If you want to compile it as a module, choose - M here. Some information is contained in the comments - at the top of <file:drivers/net/irda/old_belkin-sir.c>. - -config ACT200L_DONGLE - tristate "ACTiSYS IR-200L dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the ACTiSYS IR-200L - dongle. If you want to compile it as a module, choose M here. - The ACTiSYS IR-200L dongle attaches to the normal 9-pin serial - port connector, and can currently only be used by IrTTY. - To activate support for ACTiSYS IR-200L dongle you will have to - start irattach like this: "irattach -d act200l". - -config KINGSUN_DONGLE - tristate "KingSun/DonShine DS-620 IrDA-USB dongle" - depends on IRDA && USB - help - Say Y or M here if you want to build support for the KingSun/DonShine - DS-620 IrDA-USB bridge device driver. - - This USB bridge does not conform to the IrDA-USB device class - specification, and therefore needs its own specific driver. This - dongle supports SIR speed only (9600 bps). - - To compile it as a module, choose M here: the module will be called - kingsun-sir. - -config KSDAZZLE_DONGLE - tristate "KingSun Dazzle IrDA-USB dongle" - depends on IRDA && USB - help - Say Y or M here if you want to build support for the KingSun Dazzle - IrDA-USB bridge device driver. - - This USB bridge does not conform to the IrDA-USB device class - specification, and therefore needs its own specific driver. This - dongle supports SIR speeds only (9600 through 115200 bps). - - To compile it as a module, choose M here: the module will be called - ksdazzle-sir. - -config KS959_DONGLE - tristate "KingSun KS-959 IrDA-USB dongle" - depends on IRDA && USB - help - Say Y or M here if you want to build support for the KingSun KS-959 - IrDA-USB bridge device driver. - - This USB bridge does not conform to the IrDA-USB device class - specification, and therefore needs its own specific driver. This - dongle supports SIR speeds only (9600 through 57600 bps). - - To compile it as a module, choose M here: the module will be called - ks959-sir. - -comment "FIR device drivers" - -config USB_IRDA - tristate "IrDA USB dongles" - depends on IRDA && USB - select FW_LOADER - ---help--- - Say Y here if you want to build support for the USB IrDA FIR Dongle - device driver. To compile it as a module, choose M here: the module - will be called irda-usb. IrDA-USB support the various IrDA USB - dongles available and most of their peculiarities. Those dongles - plug in the USB port of your computer, are plug and play, and - support SIR and FIR (4Mbps) speeds. On the other hand, those - dongles tend to be less efficient than a FIR chipset. - - Please note that the driver is still experimental. And of course, - you will need both USB and IrDA support in your kernel... - -config SIGMATEL_FIR - tristate "SigmaTel STIr4200 bridge" - depends on IRDA && USB - select CRC32 - ---help--- - Say Y here if you want to build support for the SigmaTel STIr4200 - USB IrDA FIR bridge device driver. - - USB bridge based on the SigmaTel STIr4200 don't conform to the - IrDA-USB device class specification, and therefore need their - own specific driver. Those dongles support SIR and FIR (4Mbps) - speeds. - - To compile it as a module, choose M here: the module will be called - stir4200. - -config NSC_FIR - tristate "NSC PC87108/PC87338" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the NSC PC87108 and - PC87338 IrDA chipsets. This driver supports SIR, - MIR and FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - nsc-ircc. - -config WINBOND_FIR - tristate "Winbond W83977AF (IR)" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build IrDA support for the Winbond - W83977AF super-io chipset. This driver should be used for the IrDA - chipset in the Corel NetWinder. The driver supports SIR, MIR and - FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - w83977af_ir. - -config TOSHIBA_FIR - tristate "Toshiba Type-O IR Port" - depends on IRDA && PCI && !64BIT && VIRT_TO_BUS - help - Say Y here if you want to build support for the Toshiba Type-O IR - and Donau oboe chipsets. These chipsets are used by the Toshiba - Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops. - To compile it as a module, choose M here: the module will be called - donauboe. - -config AU1000_FIR - tristate "Alchemy IrDA SIR/FIR" - depends on IRDA && MIPS_ALCHEMY - help - Say Y/M here to build support the IrDA peripheral on the - Alchemy Au1000 and Au1100 SoCs. - Say M to build a module; it will be called au1k_ir.ko - -config SMC_IRCC_FIR - tristate "SMSC IrCC" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the SMC Infrared - Communications Controller. It is used in a wide variety of - laptops (Fujitsu, Sony, Compaq and some Toshiba). - To compile it as a module, choose M here: the module will be called - smsc-ircc2.o. - -config ALI_FIR - tristate "ALi M5123 FIR" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the ALi M5123 FIR - Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C, - M1535, M1535D, M1535+, M1535D South Bridge. This driver supports - SIR, MIR and FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - ali-ircc. - -config VLSI_FIR - tristate "VLSI 82C147 SIR/MIR/FIR" - depends on IRDA && PCI - help - Say Y here if you want to build support for the VLSI 82C147 - PCI-IrDA Controller. This controller is used by the HP OmniBook 800 - and 5500 notebooks. The driver provides support for SIR, MIR and - FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - vlsi_ir. - -config SA1100_FIR - tristate "SA1100 Internal IR" - depends on ARCH_SA1100 && IRDA && DMA_SA11X0 - -config VIA_FIR - tristate "VIA VT8231/VT1211 SIR/MIR/FIR" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the VIA VT8231 - and VIA VT1211 IrDA controllers, found on the motherboards using - those VIA chipsets. To use this controller, you will need - to plug a specific 5 pins FIR IrDA dongle in the specific - motherboard connector. The driver provides support for SIR, MIR - and FIR (4Mbps) speeds. - - You will need to specify the 'dongle_id' module parameter to - indicate the FIR dongle attached to the controller. - - To compile it as a module, choose M here: the module will be called - via-ircc. - -config PXA_FICP - tristate "Intel PXA2xx Internal FICP" - depends on ARCH_PXA && IRDA - help - Say Y or M here if you want to build support for the PXA2xx - built-in IRDA interface which can support both SIR and FIR. - This driver relies on platform specific helper routines so - available capabilities may vary from one PXA2xx target to - another. - -config MCS_FIR - tristate "MosChip MCS7780 IrDA-USB dongle" - depends on IRDA && USB - select CRC32 - help - Say Y or M here if you want to build support for the MosChip - MCS7780 IrDA-USB bridge device driver. - - USB bridge based on the MosChip MCS7780 don't conform to the - IrDA-USB device class specification, and therefore need their - own specific driver. Those dongles support SIR and FIR (4Mbps) - speeds. - - To compile it as a module, choose M here: the module will be called - mcs7780. - -endmenu - diff --git a/drivers/staging/irda/drivers/Makefile b/drivers/staging/irda/drivers/Makefile deleted file mode 100644 index e2901b135528..000000000000 --- a/drivers/staging/irda/drivers/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Makefile for the Linux IrDA infrared port device drivers. -# -# 9 Aug 2000, Christoph Hellwig <hch@infradead.org> -# Rewritten to use lists instead of if-statements. -# - -subdir-ccflags-y += -I$(srctree)/drivers/staging/irda/include - -# FIR drivers -obj-$(CONFIG_USB_IRDA) += irda-usb.o -obj-$(CONFIG_SIGMATEL_FIR) += stir4200.o -obj-$(CONFIG_NSC_FIR) += nsc-ircc.o -obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o -obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o -obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o -obj-$(CONFIG_SMC_IRCC_FIR) += smsc-ircc2.o -obj-$(CONFIG_ALI_FIR) += ali-ircc.o -obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o -obj-$(CONFIG_VIA_FIR) += via-ircc.o -obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o -obj-$(CONFIG_MCS_FIR) += mcs7780.o -obj-$(CONFIG_AU1000_FIR) += au1k_ir.o -# SIR drivers -obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o -obj-$(CONFIG_BFIN_SIR) += bfin_sir.o -obj-$(CONFIG_SH_SIR) += sh_sir.o -# dongle drivers for SIR drivers -obj-$(CONFIG_ESI_DONGLE) += esi-sir.o -obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o -obj-$(CONFIG_ACTISYS_DONGLE) += actisys-sir.o -obj-$(CONFIG_LITELINK_DONGLE) += litelink-sir.o -obj-$(CONFIG_GIRBIL_DONGLE) += girbil-sir.o -obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin-sir.o -obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o -obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o -obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o -obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o -obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o -obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o -obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o - -# The SIR helper module -sir-dev-objs := sir_dev.o sir_dongle.o diff --git a/drivers/staging/irda/drivers/act200l-sir.c b/drivers/staging/irda/drivers/act200l-sir.c deleted file mode 100644 index e8917511e1aa..000000000000 --- a/drivers/staging/irda/drivers/act200l-sir.c +++ /dev/null @@ -1,250 +0,0 @@ -/********************************************************************* - * - * Filename: act200l.c - * Version: 0.8 - * Description: Implementation for the ACTiSYS ACT-IR200L dongle - * Status: Experimental. - * Author: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp> - * Created at: Fri Aug 3 17:35:42 2001 - * Modified at: Fri Aug 17 10:22:40 2001 - * Modified by: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp> - * - * Copyright (c) 2001 SHIMIZU Takuya, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -static int act200l_reset(struct sir_dev *dev); -static int act200l_open(struct sir_dev *dev); -static int act200l_close(struct sir_dev *dev); -static int act200l_change_speed(struct sir_dev *dev, unsigned speed); - -/* Regsiter 0: Control register #1 */ -#define ACT200L_REG0 0x00 -#define ACT200L_TXEN 0x01 /* Enable transmitter */ -#define ACT200L_RXEN 0x02 /* Enable receiver */ - -/* Register 1: Control register #2 */ -#define ACT200L_REG1 0x10 -#define ACT200L_LODB 0x01 /* Load new baud rate count value */ -#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ - -/* Register 4: Output Power register */ -#define ACT200L_REG4 0x40 -#define ACT200L_OP0 0x01 /* Enable LED1C output */ -#define ACT200L_OP1 0x02 /* Enable LED2C output */ -#define ACT200L_BLKR 0x04 - -/* Register 5: Receive Mode register */ -#define ACT200L_REG5 0x50 -#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ - -/* Register 6: Receive Sensitivity register #1 */ -#define ACT200L_REG6 0x60 -#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ -#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ - -/* Register 7: Receive Sensitivity register #2 */ -#define ACT200L_REG7 0x70 -#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ - -/* Register 8,9: Baud Rate Dvider register #1,#2 */ -#define ACT200L_REG8 0x80 -#define ACT200L_REG9 0x90 - -#define ACT200L_2400 0x5f -#define ACT200L_9600 0x17 -#define ACT200L_19200 0x0b -#define ACT200L_38400 0x05 -#define ACT200L_57600 0x03 -#define ACT200L_115200 0x01 - -/* Register 13: Control register #3 */ -#define ACT200L_REG13 0xd0 -#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ - -/* Register 15: Status register */ -#define ACT200L_REG15 0xf0 - -/* Register 21: Control register #4 */ -#define ACT200L_REG21 0x50 -#define ACT200L_EXCK 0x02 /* Disable clock output driver */ -#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ - -static struct dongle_driver act200l = { - .owner = THIS_MODULE, - .driver_name = "ACTiSYS ACT-IR200L", - .type = IRDA_ACT200L_DONGLE, - .open = act200l_open, - .close = act200l_close, - .reset = act200l_reset, - .set_speed = act200l_change_speed, -}; - -static int __init act200l_sir_init(void) -{ - return irda_register_dongle(&act200l); -} - -static void __exit act200l_sir_cleanup(void) -{ - irda_unregister_dongle(&act200l); -} - -static int act200l_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - /* Power on the dongle */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Set the speeds we can accept */ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x03; - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int act200l_close(struct sir_dev *dev) -{ - /* Power off the dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function act200l_change_speed (dev, speed) - * - * Set the speed for the ACTiSYS ACT-IR200L type dongle. - * - */ -static int act200l_change_speed(struct sir_dev *dev, unsigned speed) -{ - u8 control[3]; - int ret = 0; - - /* Clear DTR and set RTS to enter command mode */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - - switch (speed) { - default: - ret = -EINVAL; - /* fall through */ - case 9600: - control[0] = ACT200L_REG8 | (ACT200L_9600 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f); - break; - case 19200: - control[0] = ACT200L_REG8 | (ACT200L_19200 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f); - break; - case 38400: - control[0] = ACT200L_REG8 | (ACT200L_38400 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f); - break; - case 57600: - control[0] = ACT200L_REG8 | (ACT200L_57600 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f); - break; - case 115200: - control[0] = ACT200L_REG8 | (ACT200L_115200 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f); - break; - } - control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE; - - /* Write control bytes */ - sirdev_raw_write(dev, control, 3); - msleep(5); - - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - dev->speed = speed; - return ret; -} - -/* - * Function act200l_reset (driver) - * - * Reset the ACTiSYS ACT-IR200L type dongle. - */ - -#define ACT200L_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1) -#define ACT200L_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2) - -static int act200l_reset(struct sir_dev *dev) -{ - unsigned state = dev->fsm.substate; - unsigned delay = 0; - static const u8 control[9] = { - ACT200L_REG15, - ACT200L_REG13 | ACT200L_SHDW, - ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, - ACT200L_REG13, - ACT200L_REG7 | ACT200L_ENPOS, - ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, - ACT200L_REG5 | ACT200L_RWIDL, - ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, - ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN - }; - int ret = 0; - - switch (state) { - case SIRDEV_STATE_DONGLE_RESET: - /* Reset the dongle : set RTS low for 25 ms */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - state = ACT200L_STATE_WAIT1_RESET; - delay = 50; - break; - - case ACT200L_STATE_WAIT1_RESET: - /* Clear DTR and set RTS to enter command mode */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - - udelay(25); /* better wait for some short while */ - - /* Write control bytes */ - sirdev_raw_write(dev, control, sizeof(control)); - state = ACT200L_STATE_WAIT2_RESET; - delay = 15; - break; - - case ACT200L_STATE_WAIT2_RESET: - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - dev->speed = 9600; - break; - default: - net_err_ratelimited("%s(), unknown state %d\n", - __func__, state); - ret = -1; - break; - } - dev->fsm.substate = state; - return (delay > 0) ? delay : ret; -} - -MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>"); -MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-10"); /* IRDA_ACT200L_DONGLE */ - -module_init(act200l_sir_init); -module_exit(act200l_sir_cleanup); diff --git a/drivers/staging/irda/drivers/actisys-sir.c b/drivers/staging/irda/drivers/actisys-sir.c deleted file mode 100644 index e224b8b99517..000000000000 --- a/drivers/staging/irda/drivers/actisys-sir.c +++ /dev/null @@ -1,245 +0,0 @@ -/********************************************************************* - * - * Filename: actisys.c - * Version: 1.1 - * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ - * dongles - * Status: Beta. - * Authors: Dag Brattli <dagb@cs.uit.no> (initially) - * Jean Tourrilhes <jt@hpl.hp.com> (new version) - * Martin Diehl <mad@mdiehl.de> (new version for sir_dev) - * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Sun Oct 27 22:02:13 2002 - * Modified by: Martin Diehl <mad@mdiehl.de> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 1999 Jean Tourrilhes - * Copyright (c) 2002 Martin Diehl - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -/* - * Changelog - * - * 0.8 -> 0.9999 - Jean - * o New initialisation procedure : much safer and correct - * o New procedure the change speed : much faster and simpler - * o Other cleanups & comments - * Thanks to Lichen Wang @ Actisys for his excellent help... - * - * 1.0 -> 1.1 - Martin Diehl - * modified for new sir infrastructure - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -/* - * Define the timing of the pulses we send to the dongle (to reset it, and - * to toggle speeds). Basically, the limit here is the propagation speed of - * the signals through the serial port, the dongle being much faster. Any - * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can - * go through cleanly . If you are on the wild side, you can try to lower - * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!) - */ -#define MIN_DELAY 10 /* 10 us to be on the conservative side */ - -static int actisys_open(struct sir_dev *); -static int actisys_close(struct sir_dev *); -static int actisys_change_speed(struct sir_dev *, unsigned); -static int actisys_reset(struct sir_dev *); - -/* These are the baudrates supported, in the order available */ -/* Note : the 220L doesn't support 38400, but we will fix that below */ -static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 }; - -#define MAX_SPEEDS ARRAY_SIZE(baud_rates) - -static struct dongle_driver act220l = { - .owner = THIS_MODULE, - .driver_name = "Actisys ACT-220L", - .type = IRDA_ACTISYS_DONGLE, - .open = actisys_open, - .close = actisys_close, - .reset = actisys_reset, - .set_speed = actisys_change_speed, -}; - -static struct dongle_driver act220l_plus = { - .owner = THIS_MODULE, - .driver_name = "Actisys ACT-220L+", - .type = IRDA_ACTISYS_PLUS_DONGLE, - .open = actisys_open, - .close = actisys_close, - .reset = actisys_reset, - .set_speed = actisys_change_speed, -}; - -static int __init actisys_sir_init(void) -{ - int ret; - - /* First, register an Actisys 220L dongle */ - ret = irda_register_dongle(&act220l); - if (ret < 0) - return ret; - - /* Now, register an Actisys 220L+ dongle */ - ret = irda_register_dongle(&act220l_plus); - if (ret < 0) { - irda_unregister_dongle(&act220l); - return ret; - } - return 0; -} - -static void __exit actisys_sir_cleanup(void) -{ - /* We have to remove both dongles */ - irda_unregister_dongle(&act220l_plus); - irda_unregister_dongle(&act220l); -} - -static int actisys_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Set the speeds we can accept */ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - - /* Remove support for 38400 if this is not a 220L+ dongle */ - if (dev->dongle_drv->type == IRDA_ACTISYS_DONGLE) - qos->baud_rate.bits &= ~IR_38400; - - qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int actisys_close(struct sir_dev *dev) -{ - /* Power off the dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function actisys_change_speed (task) - * - * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. - * To cycle through the available baud rates, pulse RTS low for a few us. - * - * First, we reset the dongle to always start from a known state. - * Then, we cycle through the speeds by pulsing RTS low and then up. - * The dongle allow us to pulse quite fast, se we can set speed in one go, - * which is must faster ( < 100 us) and less complex than what is found - * in some other dongle drivers... - * Note that even if the new speed is the same as the current speed, - * we reassert the speed. This make sure that things are all right, - * and it's fast anyway... - * By the way, this function will work for both type of dongles, - * because the additional speed is at the end of the sequence... - */ -static int actisys_change_speed(struct sir_dev *dev, unsigned speed) -{ - int ret = 0; - int i = 0; - - pr_debug("%s(), speed=%d (was %d)\n", __func__, speed, dev->speed); - - /* dongle was already resetted from irda_request state machine, - * we are in known state (dongle default) - */ - - /* - * Now, we can set the speed requested. Send RTS pulses until we - * reach the target speed - */ - for (i = 0; i < MAX_SPEEDS; i++) { - if (speed == baud_rates[i]) { - dev->speed = speed; - break; - } - /* Set RTS low for 10 us */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - udelay(MIN_DELAY); - - /* Set RTS high for 10 us */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - udelay(MIN_DELAY); - } - - /* Check if life is sweet... */ - if (i >= MAX_SPEEDS) { - actisys_reset(dev); - ret = -EINVAL; /* This should not happen */ - } - - /* Basta lavoro, on se casse d'ici... */ - return ret; -} - -/* - * Function actisys_reset (task) - * - * Reset the Actisys type dongle. Warning, this function must only be - * called with a process context! - * - * We need to do two things in this function : - * o first make sure that the dongle is in a state where it can operate - * o second put the dongle in a know state - * - * The dongle is powered of the RTS and DTR lines. In the dongle, there - * is a big capacitor to accommodate the current spikes. This capacitor - * takes a least 50 ms to be charged. In theory, the Bios set those lines - * up, so by the time we arrive here we should be set. It doesn't hurt - * to be on the conservative side, so we will wait... - * <Martin : move above comment to irda_config_fsm> - * Then, we set the speed to 9600 b/s to get in a known state (see in - * change_speed for details). It is needed because the IrDA stack - * has tried to set the speed immediately after our first return, - * so before we can be sure the dongle is up and running. - */ - -static int actisys_reset(struct sir_dev *dev) -{ - /* Reset the dongle : set DTR low for 10 us */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - udelay(MIN_DELAY); - - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - dev->speed = 9600; /* That's the default */ - - return 0; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>"); -MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-2"); /* IRDA_ACTISYS_DONGLE */ -MODULE_ALIAS("irda-dongle-3"); /* IRDA_ACTISYS_PLUS_DONGLE */ - -module_init(actisys_sir_init); -module_exit(actisys_sir_cleanup); diff --git a/drivers/staging/irda/drivers/ali-ircc.c b/drivers/staging/irda/drivers/ali-ircc.c deleted file mode 100644 index 589cd01797f4..000000000000 --- a/drivers/staging/irda/drivers/ali-ircc.c +++ /dev/null @@ -1,2217 +0,0 @@ -/********************************************************************* - * - * Filename: ali-ircc.h - * Version: 0.5 - * Description: Driver for the ALI M1535D and M1543C FIR Controller - * Status: Experimental. - * Author: Benjamin Kong <benjamin_kong@ali.com.tw> - * Created at: 2000/10/16 03:46PM - * Modified at: 2001/1/3 02:55PM - * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw> - * Modified at: 2003/11/6 and support for ALi south-bridge chipsets M1563 - * Modified by: Clear Zhang <clear_zhang@ali.com.tw> - * - * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/gfp.h> - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/rtnetlink.h> -#include <linux/serial_reg.h> -#include <linux/dma-mapping.h> -#include <linux/platform_device.h> - -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/byteorder.h> - -#include <net/irda/wrapper.h> -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#include "ali-ircc.h" - -#define CHIP_IO_EXTENT 8 -#define BROKEN_DONGLE_ID - -#define ALI_IRCC_DRIVER_NAME "ali-ircc" - -/* Power Management */ -static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state); -static int ali_ircc_resume(struct platform_device *dev); - -static struct platform_driver ali_ircc_driver = { - .suspend = ali_ircc_suspend, - .resume = ali_ircc_resume, - .driver = { - .name = ALI_IRCC_DRIVER_NAME, - }, -}; - -/* Module parameters */ -static int qos_mtt_bits = 0x07; /* 1 ms or more */ - -/* Use BIOS settions by default, but user may supply module parameters */ -static unsigned int io[] = { ~0, ~0, ~0, ~0 }; -static unsigned int irq[] = { 0, 0, 0, 0 }; -static unsigned int dma[] = { 0, 0, 0, 0 }; - -static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info); -static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info); -static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info); - -/* These are the currently known ALi south-bridge chipsets, the only one difference - * is that M1543C doesn't support HP HDSL-3600 - */ -static ali_chip_t chips[] = -{ - { "M1543", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x43, ali_ircc_probe_53, ali_ircc_init_43 }, - { "M1535", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x53, ali_ircc_probe_53, ali_ircc_init_53 }, - { "M1563", { 0x3f0, 0x370 }, 0x51, 0x23, 0x20, 0x63, ali_ircc_probe_53, ali_ircc_init_53 }, - { NULL } -}; - -/* Max 4 instances for now */ -static struct ali_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; - -/* Dongle Types */ -static char *dongle_types[] = { - "TFDS6000", - "HP HSDL-3600", - "HP HSDL-1100", - "No dongle connected", -}; - -/* Some prototypes */ -static int ali_ircc_open(int i, chipio_t *info); - -static int ali_ircc_close(struct ali_ircc_cb *self); - -static int ali_ircc_setup(chipio_t *info); -static int ali_ircc_is_receiving(struct ali_ircc_cb *self); -static int ali_ircc_net_open(struct net_device *dev); -static int ali_ircc_net_close(struct net_device *dev); -static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud); - -/* SIR function */ -static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, - struct net_device *dev); -static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self); -static void ali_ircc_sir_receive(struct ali_ircc_cb *self); -static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self); -static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); -static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed); - -/* FIR function */ -static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, - struct net_device *dev); -static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 speed); -static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self); -static int ali_ircc_dma_receive(struct ali_ircc_cb *self); -static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self); -static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self); -static void ali_ircc_dma_xmit(struct ali_ircc_cb *self); - -/* My Function */ -static int ali_ircc_read_dongle_id (int i, chipio_t *info); -static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed); - -/* ALi chip function */ -static void SIR2FIR(int iobase); -static void FIR2SIR(int iobase); -static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable); - -/* - * Function ali_ircc_init () - * - * Initialize chip. Find out whay kinds of chips we are dealing with - * and their configuration registers address - */ -static int __init ali_ircc_init(void) -{ - ali_chip_t *chip; - chipio_t info; - int ret; - int cfg, cfg_base; - int reg, revision; - int i = 0; - - ret = platform_driver_register(&ali_ircc_driver); - if (ret) { - net_err_ratelimited("%s, Can't register driver!\n", - ALI_IRCC_DRIVER_NAME); - return ret; - } - - ret = -ENODEV; - - /* Probe for all the ALi chipsets we know about */ - for (chip= chips; chip->name; chip++, i++) - { - pr_debug("%s(), Probing for %s ...\n", __func__, chip->name); - - /* Try all config registers for this chip */ - for (cfg=0; cfg<2; cfg++) - { - cfg_base = chip->cfg[cfg]; - if (!cfg_base) - continue; - - memset(&info, 0, sizeof(chipio_t)); - info.cfg_base = cfg_base; - info.fir_base = io[i]; - info.dma = dma[i]; - info.irq = irq[i]; - - - /* Enter Configuration */ - outb(chip->entr1, cfg_base); - outb(chip->entr2, cfg_base); - - /* Select Logical Device 5 Registers (UART2) */ - outb(0x07, cfg_base); - outb(0x05, cfg_base+1); - - /* Read Chip Identification Register */ - outb(chip->cid_index, cfg_base); - reg = inb(cfg_base+1); - - if (reg == chip->cid_value) - { - pr_debug("%s(), Chip found at 0x%03x\n", - __func__, cfg_base); - - outb(0x1F, cfg_base); - revision = inb(cfg_base+1); - pr_debug("%s(), Found %s chip, revision=%d\n", - __func__, chip->name, revision); - - /* - * If the user supplies the base address, then - * we init the chip, if not we probe the values - * set by the BIOS - */ - if (io[i] < 2000) - { - chip->init(chip, &info); - } - else - { - chip->probe(chip, &info); - } - - if (ali_ircc_open(i, &info) == 0) - ret = 0; - i++; - } - else - { - pr_debug("%s(), No %s chip at 0x%03x\n", - __func__, chip->name, cfg_base); - } - /* Exit configuration */ - outb(0xbb, cfg_base); - } - } - - if (ret) - platform_driver_unregister(&ali_ircc_driver); - - return ret; -} - -/* - * Function ali_ircc_cleanup () - * - * Close all configured chips - * - */ -static void __exit ali_ircc_cleanup(void) -{ - int i; - - for (i=0; i < ARRAY_SIZE(dev_self); i++) { - if (dev_self[i]) - ali_ircc_close(dev_self[i]); - } - - platform_driver_unregister(&ali_ircc_driver); - -} - -static const struct net_device_ops ali_ircc_sir_ops = { - .ndo_open = ali_ircc_net_open, - .ndo_stop = ali_ircc_net_close, - .ndo_start_xmit = ali_ircc_sir_hard_xmit, - .ndo_do_ioctl = ali_ircc_net_ioctl, -}; - -static const struct net_device_ops ali_ircc_fir_ops = { - .ndo_open = ali_ircc_net_open, - .ndo_stop = ali_ircc_net_close, - .ndo_start_xmit = ali_ircc_fir_hard_xmit, - .ndo_do_ioctl = ali_ircc_net_ioctl, -}; - -/* - * Function ali_ircc_open (int i, chipio_t *inf) - * - * Open driver instance - * - */ -static int ali_ircc_open(int i, chipio_t *info) -{ - struct net_device *dev; - struct ali_ircc_cb *self; - int dongle_id; - int err; - - if (i >= ARRAY_SIZE(dev_self)) { - net_err_ratelimited("%s(), maximum number of supported chips reached!\n", - __func__); - return -ENOMEM; - } - - /* Set FIR FIFO and DMA Threshold */ - if ((ali_ircc_setup(info)) == -1) - return -1; - - dev = alloc_irdadev(sizeof(*self)); - if (dev == NULL) { - net_err_ratelimited("%s(), can't allocate memory for control block!\n", - __func__); - return -ENOMEM; - } - - self = netdev_priv(dev); - self->netdev = dev; - spin_lock_init(&self->lock); - - /* Need to store self somewhere */ - dev_self[i] = self; - self->index = i; - - /* Initialize IO */ - self->io.cfg_base = info->cfg_base; /* In ali_ircc_probe_53 assign */ - self->io.fir_base = info->fir_base; /* info->sir_base = info->fir_base */ - self->io.sir_base = info->sir_base; /* ALi SIR and FIR use the same address */ - self->io.irq = info->irq; - self->io.fir_ext = CHIP_IO_EXTENT; - self->io.dma = info->dma; - self->io.fifo_size = 16; /* SIR: 16, FIR: 32 Benjamin 2000/11/1 */ - - /* Reserve the ioports that we need */ - if (!request_region(self->io.fir_base, self->io.fir_ext, - ALI_IRCC_DRIVER_NAME)) { - net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n", - __func__, self->io.fir_base); - err = -ENODEV; - goto err_out1; - } - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - /* The only value we must override it the baudrate */ - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); // benjamin 2000/11/8 05:27PM - - self->qos.min_turn_time.bits = qos_mtt_bits; - - irda_qos_bits_to_value(&self->qos); - - /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ - self->rx_buff.truesize = 14384; - self->tx_buff.truesize = 14384; - - /* Allocate memory if needed */ - self->rx_buff.head = - dma_zalloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL); - if (self->rx_buff.head == NULL) { - err = -ENOMEM; - goto err_out2; - } - - self->tx_buff.head = - dma_zalloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL); - if (self->tx_buff.head == NULL) { - err = -ENOMEM; - goto err_out3; - } - - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Tx queue info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - - /* Override the network functions we need to use */ - dev->netdev_ops = &ali_ircc_sir_ops; - - err = register_netdev(dev); - if (err) { - net_err_ratelimited("%s(), register_netdev() failed!\n", - __func__); - goto err_out4; - } - net_info_ratelimited("IrDA: Registered device %s\n", dev->name); - - /* Check dongle id */ - dongle_id = ali_ircc_read_dongle_id(i, info); - net_info_ratelimited("%s(), %s, Found dongle: %s\n", - __func__, ALI_IRCC_DRIVER_NAME, - dongle_types[dongle_id]); - - self->io.dongle_id = dongle_id; - - - return 0; - - err_out4: - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - err_out3: - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - err_out2: - release_region(self->io.fir_base, self->io.fir_ext); - err_out1: - dev_self[i] = NULL; - free_netdev(dev); - return err; -} - - -/* - * Function ali_ircc_close (self) - * - * Close driver instance - * - */ -static int __exit ali_ircc_close(struct ali_ircc_cb *self) -{ - int iobase; - - IRDA_ASSERT(self != NULL, return -1;); - - iobase = self->io.fir_base; - - /* Remove netdevice */ - unregister_netdev(self->netdev); - - /* Release the PORT that this driver is using */ - pr_debug("%s(), Releasing Region %03x\n", __func__, self->io.fir_base); - release_region(self->io.fir_base, self->io.fir_ext); - - if (self->tx_buff.head) - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - - if (self->rx_buff.head) - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - - dev_self[self->index] = NULL; - free_netdev(self->netdev); - - - return 0; -} - -/* - * Function ali_ircc_init_43 (chip, info) - * - * Initialize the ALi M1543 chip. - */ -static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info) -{ - /* All controller information like I/O address, DMA channel, IRQ - * are set by BIOS - */ - - return 0; -} - -/* - * Function ali_ircc_init_53 (chip, info) - * - * Initialize the ALi M1535 chip. - */ -static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info) -{ - /* All controller information like I/O address, DMA channel, IRQ - * are set by BIOS - */ - - return 0; -} - -/* - * Function ali_ircc_probe_53 (chip, info) - * - * Probes for the ALi M1535D or M1535 - */ -static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info) -{ - int cfg_base = info->cfg_base; - int hi, low, reg; - - - /* Enter Configuration */ - outb(chip->entr1, cfg_base); - outb(chip->entr2, cfg_base); - - /* Select Logical Device 5 Registers (UART2) */ - outb(0x07, cfg_base); - outb(0x05, cfg_base+1); - - /* Read address control register */ - outb(0x60, cfg_base); - hi = inb(cfg_base+1); - outb(0x61, cfg_base); - low = inb(cfg_base+1); - info->fir_base = (hi<<8) + low; - - info->sir_base = info->fir_base; - - pr_debug("%s(), probing fir_base=0x%03x\n", __func__, info->fir_base); - - /* Read IRQ control register */ - outb(0x70, cfg_base); - reg = inb(cfg_base+1); - info->irq = reg & 0x0f; - pr_debug("%s(), probing irq=%d\n", __func__, info->irq); - - /* Read DMA channel */ - outb(0x74, cfg_base); - reg = inb(cfg_base+1); - info->dma = reg & 0x07; - - if(info->dma == 0x04) - net_warn_ratelimited("%s(), No DMA channel assigned !\n", - __func__); - else - pr_debug("%s(), probing dma=%d\n", __func__, info->dma); - - /* Read Enabled Status */ - outb(0x30, cfg_base); - reg = inb(cfg_base+1); - info->enabled = (reg & 0x80) && (reg & 0x01); - pr_debug("%s(), probing enabled=%d\n", __func__, info->enabled); - - /* Read Power Status */ - outb(0x22, cfg_base); - reg = inb(cfg_base+1); - info->suspended = (reg & 0x20); - pr_debug("%s(), probing suspended=%d\n", __func__, info->suspended); - - /* Exit configuration */ - outb(0xbb, cfg_base); - - - return 0; -} - -/* - * Function ali_ircc_setup (info) - * - * Set FIR FIFO and DMA Threshold - * Returns non-negative on success. - * - */ -static int ali_ircc_setup(chipio_t *info) -{ - unsigned char tmp; - int version; - int iobase = info->fir_base; - - - /* Locking comments : - * Most operations here need to be protected. We are called before - * the device instance is created in ali_ircc_open(), therefore - * nobody can bother us - Jean II */ - - /* Switch to FIR space */ - SIR2FIR(iobase); - - /* Master Reset */ - outb(0x40, iobase+FIR_MCR); // benjamin 2000/11/30 11:45AM - - /* Read FIR ID Version Register */ - switch_bank(iobase, BANK3); - version = inb(iobase+FIR_ID_VR); - - /* Should be 0x00 in the M1535/M1535D */ - if(version != 0x00) - { - net_err_ratelimited("%s, Wrong chip version %02x\n", - ALI_IRCC_DRIVER_NAME, version); - return -1; - } - - /* Set FIR FIFO Threshold Register */ - switch_bank(iobase, BANK1); - outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); - - /* Set FIR DMA Threshold Register */ - outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); - - /* CRC enable */ - switch_bank(iobase, BANK2); - outb(inb(iobase+FIR_IRDA_CR) | IRDA_CR_CRC, iobase+FIR_IRDA_CR); - - /* NDIS driver set TX Length here BANK2 Alias 3, Alias4*/ - - /* Switch to Bank 0 */ - switch_bank(iobase, BANK0); - - tmp = inb(iobase+FIR_LCR_B); - tmp &=~0x20; // disable SIP - tmp |= 0x80; // these two steps make RX mode - tmp &= 0xbf; - outb(tmp, iobase+FIR_LCR_B); - - /* Disable Interrupt */ - outb(0x00, iobase+FIR_IER); - - - /* Switch to SIR space */ - FIR2SIR(iobase); - - net_info_ratelimited("%s, driver loaded (Benjamin Kong)\n", - ALI_IRCC_DRIVER_NAME); - - /* Enable receive interrupts */ - // outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM - // Turn on the interrupts in ali_ircc_net_open - - - return 0; -} - -/* - * Function ali_ircc_read_dongle_id (int index, info) - * - * Try to read dongle identification. This procedure needs to be executed - * once after power-on/reset. It also needs to be used whenever you suspect - * that the user may have plugged/unplugged the IrDA Dongle. - */ -static int ali_ircc_read_dongle_id (int i, chipio_t *info) -{ - int dongle_id, reg; - int cfg_base = info->cfg_base; - - - /* Enter Configuration */ - outb(chips[i].entr1, cfg_base); - outb(chips[i].entr2, cfg_base); - - /* Select Logical Device 5 Registers (UART2) */ - outb(0x07, cfg_base); - outb(0x05, cfg_base+1); - - /* Read Dongle ID */ - outb(0xf0, cfg_base); - reg = inb(cfg_base+1); - dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01); - pr_debug("%s(), probing dongle_id=%d, dongle_types=%s\n", - __func__, dongle_id, dongle_types[dongle_id]); - - /* Exit configuration */ - outb(0xbb, cfg_base); - - - return dongle_id; -} - -/* - * Function ali_ircc_interrupt (irq, dev_id, regs) - * - * An interrupt from the chip has arrived. Time to do some work - * - */ -static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct ali_ircc_cb *self; - int ret; - - - self = netdev_priv(dev); - - spin_lock(&self->lock); - - /* Dispatch interrupt handler for the current speed */ - if (self->io.speed > 115200) - ret = ali_ircc_fir_interrupt(self); - else - ret = ali_ircc_sir_interrupt(self); - - spin_unlock(&self->lock); - - return ret; -} -/* - * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self) - * - * Handle MIR/FIR interrupt - * - */ -static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self) -{ - __u8 eir, OldMessageCount; - int iobase, tmp; - - - iobase = self->io.fir_base; - - switch_bank(iobase, BANK0); - self->InterruptID = inb(iobase+FIR_IIR); - self->BusStatus = inb(iobase+FIR_BSR); - - OldMessageCount = (self->LineStatus + 1) & 0x07; - self->LineStatus = inb(iobase+FIR_LSR); - //self->ier = inb(iobase+FIR_IER); 2000/12/1 04:32PM - eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ - - pr_debug("%s(), self->InterruptID = %x\n", __func__, self->InterruptID); - pr_debug("%s(), self->LineStatus = %x\n", __func__, self->LineStatus); - pr_debug("%s(), self->ier = %x\n", __func__, self->ier); - pr_debug("%s(), eir = %x\n", __func__, eir); - - /* Disable interrupts */ - SetCOMInterrupts(self, FALSE); - - /* Tx or Rx Interrupt */ - - if (eir & IIR_EOM) - { - if (self->io.direction == IO_XMIT) /* TX */ - { - pr_debug("%s(), ******* IIR_EOM (Tx) *******\n", - __func__); - - if(ali_ircc_dma_xmit_complete(self)) - { - if (irda_device_txqueue_empty(self->netdev)) - { - /* Prepare for receive */ - ali_ircc_dma_receive(self); - self->ier = IER_EOM; - } - } - else - { - self->ier = IER_EOM; - } - - } - else /* RX */ - { - pr_debug("%s(), ******* IIR_EOM (Rx) *******\n", - __func__); - - if(OldMessageCount > ((self->LineStatus+1) & 0x07)) - { - self->rcvFramesOverflow = TRUE; - pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE ********\n", - __func__); - } - - if (ali_ircc_dma_receive_complete(self)) - { - pr_debug("%s(), ******* receive complete ********\n", - __func__); - - self->ier = IER_EOM; - } - else - { - pr_debug("%s(), ******* Not receive complete ********\n", - __func__); - - self->ier = IER_EOM | IER_TIMER; - } - - } - } - /* Timer Interrupt */ - else if (eir & IIR_TIMER) - { - if(OldMessageCount > ((self->LineStatus+1) & 0x07)) - { - self->rcvFramesOverflow = TRUE; - pr_debug("%s(), ******* self->rcvFramesOverflow = TRUE *******\n", - __func__); - } - /* Disable Timer */ - switch_bank(iobase, BANK1); - tmp = inb(iobase+FIR_CR); - outb( tmp& ~CR_TIMER_EN, iobase+FIR_CR); - - /* Check if this is a Tx timer interrupt */ - if (self->io.direction == IO_XMIT) - { - ali_ircc_dma_xmit(self); - - /* Interrupt on EOM */ - self->ier = IER_EOM; - - } - else /* Rx */ - { - if(ali_ircc_dma_receive_complete(self)) - { - self->ier = IER_EOM; - } - else - { - self->ier = IER_EOM | IER_TIMER; - } - } - } - - /* Restore Interrupt */ - SetCOMInterrupts(self, TRUE); - - return IRQ_RETVAL(eir); -} - -/* - * Function ali_ircc_sir_interrupt (irq, self, eir) - * - * Handle SIR interrupt - * - */ -static irqreturn_t ali_ircc_sir_interrupt(struct ali_ircc_cb *self) -{ - int iobase; - int iir, lsr; - - - iobase = self->io.sir_base; - - iir = inb(iobase+UART_IIR) & UART_IIR_ID; - if (iir) { - /* Clear interrupt */ - lsr = inb(iobase+UART_LSR); - - pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n", - __func__, iir, lsr, iobase); - - switch (iir) - { - case UART_IIR_RLSI: - pr_debug("%s(), RLSI\n", __func__); - break; - case UART_IIR_RDI: - /* Receive interrupt */ - ali_ircc_sir_receive(self); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) - { - /* Transmitter ready for data */ - ali_ircc_sir_write_wakeup(self); - } - break; - default: - pr_debug("%s(), unhandled IIR=%#x\n", - __func__, iir); - break; - } - - } - - - return IRQ_RETVAL(iir); -} - - -/* - * Function ali_ircc_sir_receive (self) - * - * Receive one frame from the infrared port - * - */ -static void ali_ircc_sir_receive(struct ali_ircc_cb *self) -{ - int boguscount = 0; - int iobase; - - IRDA_ASSERT(self != NULL, return;); - - iobase = self->io.sir_base; - - /* - * Receive all characters in Rx FIFO, unwrap and unstuff them. - * async_unwrap_char will deliver all found frames - */ - do { - async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, - inb(iobase+UART_RX)); - - /* Make sure we don't stay here too long */ - if (boguscount++ > 32) { - pr_debug("%s(), breaking!\n", __func__); - break; - } - } while (inb(iobase+UART_LSR) & UART_LSR_DR); - -} - -/* - * Function ali_ircc_sir_write_wakeup (tty) - * - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - * - */ -static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self) -{ - int actual = 0; - int iobase; - - IRDA_ASSERT(self != NULL, return;); - - - iobase = self->io.sir_base; - - /* Finished with frame? */ - if (self->tx_buff.len > 0) - { - /* Write data left in transmit buffer */ - actual = ali_ircc_sir_write(iobase, self->io.fifo_size, - self->tx_buff.data, self->tx_buff.len); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - } - else - { - if (self->new_speed) - { - /* We must wait until all data are gone */ - while(!(inb(iobase+UART_LSR) & UART_LSR_TEMT)) - pr_debug("%s(), UART_LSR_THRE\n", __func__); - - pr_debug("%s(), Changing speed! self->new_speed = %d\n", - __func__, self->new_speed); - ali_ircc_change_speed(self, self->new_speed); - self->new_speed = 0; - - // benjamin 2000/11/10 06:32PM - if (self->io.speed > 115200) - { - pr_debug("%s(), ali_ircc_change_speed from UART_LSR_TEMT\n", - __func__); - - self->ier = IER_EOM; - // SetCOMInterrupts(self, TRUE); - return; - } - } - else - { - netif_wake_queue(self->netdev); - } - - self->netdev->stats.tx_packets++; - - /* Turn on receive interrupts */ - outb(UART_IER_RDI, iobase+UART_IER); - } - -} - -static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud) -{ - struct net_device *dev = self->netdev; - int iobase; - - - pr_debug("%s(), setting speed = %d\n", __func__, baud); - - /* This function *must* be called with irq off and spin-lock. - * - Jean II */ - - iobase = self->io.fir_base; - - SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM - - /* Go to MIR, FIR Speed */ - if (baud > 115200) - { - - - ali_ircc_fir_change_speed(self, baud); - - /* Install FIR xmit handler*/ - dev->netdev_ops = &ali_ircc_fir_ops; - - /* Enable Interuupt */ - self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM - - /* Be ready for incoming frames */ - ali_ircc_dma_receive(self); // benajmin 2000/11/8 07:46PM not complete - } - /* Go to SIR Speed */ - else - { - ali_ircc_sir_change_speed(self, baud); - - /* Install SIR xmit handler*/ - dev->netdev_ops = &ali_ircc_sir_ops; - } - - - SetCOMInterrupts(self, TRUE); // 2000/11/24 11:43AM - - netif_wake_queue(self->netdev); - -} - -static void ali_ircc_fir_change_speed(struct ali_ircc_cb *priv, __u32 baud) -{ - - int iobase; - struct ali_ircc_cb *self = priv; - struct net_device *dev; - - - IRDA_ASSERT(self != NULL, return;); - - dev = self->netdev; - iobase = self->io.fir_base; - - pr_debug("%s(), self->io.speed = %d, change to speed = %d\n", - __func__, self->io.speed, baud); - - /* Come from SIR speed */ - if(self->io.speed <=115200) - { - SIR2FIR(iobase); - } - - /* Update accounting for new speed */ - self->io.speed = baud; - - // Set Dongle Speed mode - ali_ircc_change_dongle_speed(self, baud); - -} - -/* - * Function ali_sir_change_speed (self, speed) - * - * Set speed of IrDA port to specified baudrate - * - */ -static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed) -{ - struct ali_ircc_cb *self = priv; - int iobase; - int fcr; /* FIFO control reg */ - int lcr; /* Line control reg */ - int divisor; - - - pr_debug("%s(), Setting speed to: %d\n", __func__, speed); - - IRDA_ASSERT(self != NULL, return;); - - iobase = self->io.sir_base; - - /* Come from MIR or FIR speed */ - if(self->io.speed >115200) - { - // Set Dongle Speed mode first - ali_ircc_change_dongle_speed(self, speed); - - FIR2SIR(iobase); - } - - // Clear Line and Auxiluary status registers 2000/11/24 11:47AM - - inb(iobase+UART_LSR); - inb(iobase+UART_SCR); - - /* Update accounting for new speed */ - self->io.speed = speed; - - divisor = 115200/speed; - - fcr = UART_FCR_ENABLE_FIFO; - - /* - * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and - * almost 1,7 ms at 19200 bps. At speeds above that we can just forget - * about this timeout since it will always be fast enough. - */ - if (self->io.speed < 38400) - fcr |= UART_FCR_TRIGGER_1; - else - fcr |= UART_FCR_TRIGGER_14; - - /* IrDA ports use 8N1 */ - lcr = UART_LCR_WLEN8; - - outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */ - outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */ - outb(divisor >> 8, iobase+UART_DLM); - outb(lcr, iobase+UART_LCR); /* Set 8N1 */ - outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ - - /* without this, the connection will be broken after come back from FIR speed, - but with this, the SIR connection is harder to established */ - outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); -} - -static void ali_ircc_change_dongle_speed(struct ali_ircc_cb *priv, int speed) -{ - - struct ali_ircc_cb *self = priv; - int iobase,dongle_id; - int tmp = 0; - - - iobase = self->io.fir_base; /* or iobase = self->io.sir_base; */ - dongle_id = self->io.dongle_id; - - /* We are already locked, no need to do it again */ - - pr_debug("%s(), Set Speed for %s , Speed = %d\n", - __func__, dongle_types[dongle_id], speed); - - switch_bank(iobase, BANK2); - tmp = inb(iobase+FIR_IRDA_CR); - - /* IBM type dongle */ - if(dongle_id == 0) - { - if(speed == 4000000) - { - // __ __ - // SD/MODE __| |__ __ - // __ __ - // IRTX __ __| |__ - // T1 T2 T3 T4 T5 - - tmp &= ~IRDA_CR_HDLC; // HDLC=0 - tmp |= IRDA_CR_CRC; // CRC=1 - - switch_bank(iobase, BANK2); - outb(tmp, iobase+FIR_IRDA_CR); - - // T1 -> SD/MODE:0 IRTX:0 - tmp &= ~0x09; - tmp |= 0x02; - outb(tmp, iobase+FIR_IRDA_CR); - udelay(2); - - // T2 -> SD/MODE:1 IRTX:0 - tmp &= ~0x01; - tmp |= 0x0a; - outb(tmp, iobase+FIR_IRDA_CR); - udelay(2); - - // T3 -> SD/MODE:1 IRTX:1 - tmp |= 0x0b; - outb(tmp, iobase+FIR_IRDA_CR); - udelay(2); - - // T4 -> SD/MODE:0 IRTX:1 - tmp &= ~0x08; - tmp |= 0x03; - outb(tmp, iobase+FIR_IRDA_CR); - udelay(2); - - // T5 -> SD/MODE:0 IRTX:0 - tmp &= ~0x09; - tmp |= 0x02; - outb(tmp, iobase+FIR_IRDA_CR); - udelay(2); - - // reset -> Normal TX output Signal - outb(tmp & ~0x02, iobase+FIR_IRDA_CR); - } - else /* speed <=1152000 */ - { - // __ - // SD/MODE __| |__ - // - // IRTX ________ - // T1 T2 T3 - - /* MIR 115200, 57600 */ - if (speed==1152000) - { - tmp |= 0xA0; //HDLC=1, 1.152Mbps=1 - } - else - { - tmp &=~0x80; //HDLC 0.576Mbps - tmp |= 0x20; //HDLC=1, - } - - tmp |= IRDA_CR_CRC; // CRC=1 - - switch_bank(iobase, BANK2); - outb(tmp, iobase+FIR_IRDA_CR); - - /* MIR 115200, 57600 */ - - //switch_bank(iobase, BANK2); - // T1 -> SD/MODE:0 IRTX:0 - tmp &= ~0x09; - tmp |= 0x02; - outb(tmp, iobase+FIR_IRDA_CR); - udelay(2); - - // T2 -> SD/MODE:1 IRTX:0 - tmp &= ~0x01; - tmp |= 0x0a; - outb(tmp, iobase+FIR_IRDA_CR); - - // T3 -> SD/MODE:0 IRTX:0 - tmp &= ~0x09; - tmp |= 0x02; - outb(tmp, iobase+FIR_IRDA_CR); - udelay(2); - - // reset -> Normal TX output Signal - outb(tmp & ~0x02, iobase+FIR_IRDA_CR); - } - } - else if (dongle_id == 1) /* HP HDSL-3600 */ - { - switch(speed) - { - case 4000000: - tmp &= ~IRDA_CR_HDLC; // HDLC=0 - break; - - case 1152000: - tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 - break; - - case 576000: - tmp &=~0x80; // HDLC 0.576Mbps - tmp |= 0x20; // HDLC=1, - break; - } - - tmp |= IRDA_CR_CRC; // CRC=1 - - switch_bank(iobase, BANK2); - outb(tmp, iobase+FIR_IRDA_CR); - } - else /* HP HDSL-1100 */ - { - if(speed <= 115200) /* SIR */ - { - - tmp &= ~IRDA_CR_FIR_SIN; // HP sin select = 0 - - switch_bank(iobase, BANK2); - outb(tmp, iobase+FIR_IRDA_CR); - } - else /* MIR FIR */ - { - - switch(speed) - { - case 4000000: - tmp &= ~IRDA_CR_HDLC; // HDLC=0 - break; - - case 1152000: - tmp |= 0xA0; // HDLC=1, 1.152Mbps=1 - break; - - case 576000: - tmp &=~0x80; // HDLC 0.576Mbps - tmp |= 0x20; // HDLC=1, - break; - } - - tmp |= IRDA_CR_CRC; // CRC=1 - tmp |= IRDA_CR_FIR_SIN; // HP sin select = 1 - - switch_bank(iobase, BANK2); - outb(tmp, iobase+FIR_IRDA_CR); - } - } - - switch_bank(iobase, BANK0); - -} - -/* - * Function ali_ircc_sir_write (driver) - * - * Fill Tx FIFO with transmit data - * - */ -static int ali_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) -{ - int actual = 0; - - - /* Tx FIFO should be empty! */ - if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - pr_debug("%s(), failed, fifo not empty!\n", __func__); - return 0; - } - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual], iobase+UART_TX); - - actual++; - } - - return actual; -} - -/* - * Function ali_ircc_net_open (dev) - * - * Start the device - * - */ -static int ali_ircc_net_open(struct net_device *dev) -{ - struct ali_ircc_cb *self; - int iobase; - char hwname[32]; - - - IRDA_ASSERT(dev != NULL, return -1;); - - self = netdev_priv(dev); - - IRDA_ASSERT(self != NULL, return 0;); - - iobase = self->io.fir_base; - - /* Request IRQ and install Interrupt Handler */ - if (request_irq(self->io.irq, ali_ircc_interrupt, 0, dev->name, dev)) - { - net_warn_ratelimited("%s, unable to allocate irq=%d\n", - ALI_IRCC_DRIVER_NAME, self->io.irq); - return -EAGAIN; - } - - /* - * Always allocate the DMA channel after the IRQ, and clean up on - * failure. - */ - if (request_dma(self->io.dma, dev->name)) { - net_warn_ratelimited("%s, unable to allocate dma=%d\n", - ALI_IRCC_DRIVER_NAME, self->io.dma); - free_irq(self->io.irq, dev); - return -EAGAIN; - } - - /* Turn on interrups */ - outb(UART_IER_RDI , iobase+UART_IER); - - /* Ready to play! */ - netif_start_queue(dev); //benjamin by irport - - /* Give self a hardware name */ - sprintf(hwname, "ALI-FIR @ 0x%03x", self->io.fir_base); - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos, hwname); - - - return 0; -} - -/* - * Function ali_ircc_net_close (dev) - * - * Stop the device - * - */ -static int ali_ircc_net_close(struct net_device *dev) -{ - - struct ali_ircc_cb *self; - //int iobase; - - - IRDA_ASSERT(dev != NULL, return -1;); - - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); - - /* Stop device */ - netif_stop_queue(dev); - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - disable_dma(self->io.dma); - - /* Disable interrupts */ - SetCOMInterrupts(self, FALSE); - - free_irq(self->io.irq, dev); - free_dma(self->io.dma); - - - return 0; -} - -/* - * Function ali_ircc_fir_hard_xmit (skb, dev) - * - * Transmit the frame - * - */ -static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct ali_ircc_cb *self; - unsigned long flags; - int iobase; - __u32 speed; - int mtt, diff; - - - self = netdev_priv(dev); - iobase = self->io.fir_base; - - netif_stop_queue(dev); - - /* Make sure tests *& speed change are atomic */ - spin_lock_irqsave(&self->lock, flags); - - /* Note : you should make sure that speed changes are not going - * to corrupt any outgoing frame. Look at nsc-ircc for the gory - * details - Jean II */ - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - /* Check for empty frame */ - if (!skb->len) { - ali_ircc_change_speed(self, speed); - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else - self->new_speed = speed; - } - - /* Register and copy this frame to DMA memory */ - self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; - self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; - self->tx_fifo.tail += skb->len; - - dev->stats.tx_bytes += skb->len; - - skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, - skb->len); - self->tx_fifo.len++; - self->tx_fifo.free++; - - /* Start transmit only if there is currently no transmit going on */ - if (self->tx_fifo.len == 1) - { - /* Check if we must wait the min turn time or not */ - mtt = irda_get_mtt(skb); - - if (mtt) - { - /* Check how much time we have used already */ - diff = ktime_us_delta(ktime_get(), self->stamp); - /* self->stamp is set from ali_ircc_dma_receive_complete() */ - - pr_debug("%s(), ******* diff = %d *******\n", - __func__, diff); - - /* Check if the mtt is larger than the time we have - * already used by all the protocol processing - */ - if (mtt > diff) - { - mtt -= diff; - - /* - * Use timer if delay larger than 1000 us, and - * use udelay for smaller values which should - * be acceptable - */ - if (mtt > 500) - { - /* Adjust for timer resolution */ - mtt = (mtt+250) / 500; /* 4 discard, 5 get advanced, Let's round off */ - - pr_debug("%s(), ************** mtt = %d ***********\n", - __func__, mtt); - - /* Setup timer */ - if (mtt == 1) /* 500 us */ - { - switch_bank(iobase, BANK1); - outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); - } - else if (mtt == 2) /* 1 ms */ - { - switch_bank(iobase, BANK1); - outb(TIMER_IIR_1ms, iobase+FIR_TIMER_IIR); - } - else /* > 2ms -> 4ms */ - { - switch_bank(iobase, BANK1); - outb(TIMER_IIR_2ms, iobase+FIR_TIMER_IIR); - } - - - /* Start timer */ - outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); - self->io.direction = IO_XMIT; - - /* Enable timer interrupt */ - self->ier = IER_TIMER; - SetCOMInterrupts(self, TRUE); - - /* Timer will take care of the rest */ - goto out; - } - else - udelay(mtt); - } // if (if (mtt > diff) - }// if (mtt) - - /* Enable EOM interrupt */ - self->ier = IER_EOM; - SetCOMInterrupts(self, TRUE); - - /* Transmit frame */ - ali_ircc_dma_xmit(self); - } // if (self->tx_fifo.len == 1) - - out: - - /* Not busy transmitting anymore if window is not full */ - if (self->tx_fifo.free < MAX_TX_WINDOW) - netif_wake_queue(self->netdev); - - /* Restore bank register */ - switch_bank(iobase, BANK0); - - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - - -static void ali_ircc_dma_xmit(struct ali_ircc_cb *self) -{ - int iobase, tmp; - unsigned char FIFO_OPTI, Hi, Lo; - - - - iobase = self->io.fir_base; - - /* FIFO threshold , this method comes from NDIS5 code */ - - if(self->tx_fifo.queue[self->tx_fifo.ptr].len < TX_FIFO_Threshold) - FIFO_OPTI = self->tx_fifo.queue[self->tx_fifo.ptr].len-1; - else - FIFO_OPTI = TX_FIFO_Threshold; - - /* Disable DMA */ - switch_bank(iobase, BANK1); - outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); - - self->io.direction = IO_XMIT; - - irda_setup_dma(self->io.dma, - ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start - - self->tx_buff.head) + self->tx_buff_dma, - self->tx_fifo.queue[self->tx_fifo.ptr].len, - DMA_TX_MODE); - - /* Reset Tx FIFO */ - switch_bank(iobase, BANK0); - outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); - - /* Set Tx FIFO threshold */ - if (self->fifo_opti_buf!=FIFO_OPTI) - { - switch_bank(iobase, BANK1); - outb(FIFO_OPTI, iobase+FIR_FIFO_TR) ; - self->fifo_opti_buf=FIFO_OPTI; - } - - /* Set Tx DMA threshold */ - switch_bank(iobase, BANK1); - outb(TX_DMA_Threshold, iobase+FIR_DMA_TR); - - /* Set max Tx frame size */ - Hi = (self->tx_fifo.queue[self->tx_fifo.ptr].len >> 8) & 0x0f; - Lo = self->tx_fifo.queue[self->tx_fifo.ptr].len & 0xff; - switch_bank(iobase, BANK2); - outb(Hi, iobase+FIR_TX_DSR_HI); - outb(Lo, iobase+FIR_TX_DSR_LO); - - /* Disable SIP , Disable Brick Wall (we don't support in TX mode), Change to TX mode */ - switch_bank(iobase, BANK0); - tmp = inb(iobase+FIR_LCR_B); - tmp &= ~0x20; // Disable SIP - outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B); - pr_debug("%s(), *** Change to TX mode: FIR_LCR_B = 0x%x ***\n", - __func__, inb(iobase + FIR_LCR_B)); - - outb(0, iobase+FIR_LSR); - - /* Enable DMA and Burst Mode */ - switch_bank(iobase, BANK1); - outb(inb(iobase+FIR_CR) | CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); - - switch_bank(iobase, BANK0); - -} - -static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) -{ - int iobase; - int ret = TRUE; - - - iobase = self->io.fir_base; - - /* Disable DMA */ - switch_bank(iobase, BANK1); - outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); - - /* Check for underrun! */ - switch_bank(iobase, BANK0); - if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT) - - { - net_err_ratelimited("%s(), ********* LSR_FRAME_ABORT *********\n", - __func__); - self->netdev->stats.tx_errors++; - self->netdev->stats.tx_fifo_errors++; - } - else - { - self->netdev->stats.tx_packets++; - } - - /* Check if we need to change the speed */ - if (self->new_speed) - { - ali_ircc_change_speed(self, self->new_speed); - self->new_speed = 0; - } - - /* Finished with this frame, so prepare for next */ - self->tx_fifo.ptr++; - self->tx_fifo.len--; - - /* Any frames to be sent back-to-back? */ - if (self->tx_fifo.len) - { - ali_ircc_dma_xmit(self); - - /* Not finished yet! */ - ret = FALSE; - } - else - { /* Reset Tx FIFO info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - } - - /* Make sure we have room for more frames */ - if (self->tx_fifo.free < MAX_TX_WINDOW) { - /* Not busy transmitting anymore */ - /* Tell the network layer, that we can accept more frames */ - netif_wake_queue(self->netdev); - } - - switch_bank(iobase, BANK0); - - return ret; -} - -/* - * Function ali_ircc_dma_receive (self) - * - * Get ready for receiving a frame. The device will initiate a DMA - * if it starts to receive a frame. - * - */ -static int ali_ircc_dma_receive(struct ali_ircc_cb *self) -{ - int iobase, tmp; - - - iobase = self->io.fir_base; - - /* Reset Tx FIFO info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - - /* Disable DMA */ - switch_bank(iobase, BANK1); - outb(inb(iobase+FIR_CR) & ~CR_DMA_EN, iobase+FIR_CR); - - /* Reset Message Count */ - switch_bank(iobase, BANK0); - outb(0x07, iobase+FIR_LSR); - - self->rcvFramesOverflow = FALSE; - - self->LineStatus = inb(iobase+FIR_LSR) ; - - /* Reset Rx FIFO info */ - self->io.direction = IO_RECV; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Rx FIFO */ - // switch_bank(iobase, BANK0); - outb(LCR_A_FIFO_RESET, iobase+FIR_LCR_A); - - self->st_fifo.len = self->st_fifo.pending_bytes = 0; - self->st_fifo.tail = self->st_fifo.head = 0; - - irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, - DMA_RX_MODE); - - /* Set Receive Mode,Brick Wall */ - //switch_bank(iobase, BANK0); - tmp = inb(iobase+FIR_LCR_B); - outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM - pr_debug("%s(), *** Change To RX mode: FIR_LCR_B = 0x%x ***\n", - __func__, inb(iobase + FIR_LCR_B)); - - /* Set Rx Threshold */ - switch_bank(iobase, BANK1); - outb(RX_FIFO_Threshold, iobase+FIR_FIFO_TR); - outb(RX_DMA_Threshold, iobase+FIR_DMA_TR); - - /* Enable DMA and Burst Mode */ - // switch_bank(iobase, BANK1); - outb(CR_DMA_EN | CR_DMA_BURST, iobase+FIR_CR); - - switch_bank(iobase, BANK0); - return 0; -} - -static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) -{ - struct st_fifo *st_fifo; - struct sk_buff *skb; - __u8 status, MessageCount; - int len, i, iobase, val; - - st_fifo = &self->st_fifo; - iobase = self->io.fir_base; - - switch_bank(iobase, BANK0); - MessageCount = inb(iobase+ FIR_LSR)&0x07; - - if (MessageCount > 0) - pr_debug("%s(), Message count = %d\n", __func__, MessageCount); - - for (i=0; i<=MessageCount; i++) - { - /* Bank 0 */ - switch_bank(iobase, BANK0); - status = inb(iobase+FIR_LSR); - - switch_bank(iobase, BANK2); - len = inb(iobase+FIR_RX_DSR_HI) & 0x0f; - len = len << 8; - len |= inb(iobase+FIR_RX_DSR_LO); - - pr_debug("%s(), RX Length = 0x%.2x,\n", __func__ , len); - pr_debug("%s(), RX Status = 0x%.2x,\n", __func__ , status); - - if (st_fifo->tail >= MAX_RX_WINDOW) { - pr_debug("%s(), window is full!\n", __func__); - continue; - } - - st_fifo->entries[st_fifo->tail].status = status; - st_fifo->entries[st_fifo->tail].len = len; - st_fifo->pending_bytes += len; - st_fifo->tail++; - st_fifo->len++; - } - - for (i=0; i<=MessageCount; i++) - { - /* Get first entry */ - status = st_fifo->entries[st_fifo->head].status; - len = st_fifo->entries[st_fifo->head].len; - st_fifo->pending_bytes -= len; - st_fifo->head++; - st_fifo->len--; - - /* Check for errors */ - if ((status & 0xd8) || self->rcvFramesOverflow || (len==0)) - { - pr_debug("%s(), ************* RX Errors ************\n", - __func__); - - /* Skip frame */ - self->netdev->stats.rx_errors++; - - self->rx_buff.data += len; - - if (status & LSR_FIFO_UR) - { - self->netdev->stats.rx_frame_errors++; - pr_debug("%s(), ************* FIFO Errors ************\n", - __func__); - } - if (status & LSR_FRAME_ERROR) - { - self->netdev->stats.rx_frame_errors++; - pr_debug("%s(), ************* FRAME Errors ************\n", - __func__); - } - - if (status & LSR_CRC_ERROR) - { - self->netdev->stats.rx_crc_errors++; - pr_debug("%s(), ************* CRC Errors ************\n", - __func__); - } - - if(self->rcvFramesOverflow) - { - self->netdev->stats.rx_frame_errors++; - pr_debug("%s(), ************* Overran DMA buffer ************\n", - __func__); - } - if(len == 0) - { - self->netdev->stats.rx_frame_errors++; - pr_debug("%s(), ********** Receive Frame Size = 0 *********\n", - __func__); - } - } - else - { - - if (st_fifo->pending_bytes < 32) - { - switch_bank(iobase, BANK0); - val = inb(iobase+FIR_BSR); - if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) - { - pr_debug("%s(), ************* BSR_FIFO_NOT_EMPTY ************\n", - __func__); - - /* Put this entry back in fifo */ - st_fifo->head--; - st_fifo->len++; - st_fifo->pending_bytes += len; - st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[st_fifo->head].len = len; - - /* - * DMA not finished yet, so try again - * later, set timer value, resolution - * 500 us - */ - - switch_bank(iobase, BANK1); - outb(TIMER_IIR_500, iobase+FIR_TIMER_IIR); // 2001/1/2 05:07PM - - /* Enable Timer */ - outb(inb(iobase+FIR_CR) | CR_TIMER_EN, iobase+FIR_CR); - - return FALSE; /* I'll be back! */ - } - } - - /* - * Remember the time we received this frame, so we can - * reduce the min turn time a bit since we will know - * how much time we have used for protocol processing - */ - self->stamp = ktime_get(); - - skb = dev_alloc_skb(len+1); - if (!skb) { - self->netdev->stats.rx_dropped++; - - return FALSE; - } - - /* Make sure IP header gets aligned */ - skb_reserve(skb, 1); - - /* Copy frame without CRC, CRC is removed by hardware*/ - skb_put(skb, len); - skb_copy_to_linear_data(skb, self->rx_buff.data, len); - - /* Move to next frame */ - self->rx_buff.data += len; - self->netdev->stats.rx_bytes += len; - self->netdev->stats.rx_packets++; - - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - } - } - - switch_bank(iobase, BANK0); - - return TRUE; -} - - - -/* - * Function ali_ircc_sir_hard_xmit (skb, dev) - * - * Transmit the frame! - * - */ -static netdev_tx_t ali_ircc_sir_hard_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct ali_ircc_cb *self; - unsigned long flags; - int iobase; - __u32 speed; - - - IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); - - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); - - iobase = self->io.sir_base; - - netif_stop_queue(dev); - - /* Make sure tests *& speed change are atomic */ - spin_lock_irqsave(&self->lock, flags); - - /* Note : you should make sure that speed changes are not going - * to corrupt any outgoing frame. Look at nsc-ircc for the gory - * details - Jean II */ - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - /* Check for empty frame */ - if (!skb->len) { - ali_ircc_change_speed(self, speed); - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else - self->new_speed = speed; - } - - /* Init tx buffer */ - self->tx_buff.data = self->tx_buff.head; - - /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - self->netdev->stats.tx_bytes += self->tx_buff.len; - - /* Turn on transmit finished interrupt. Will fire immediately! */ - outb(UART_IER_THRI, iobase+UART_IER); - - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - - dev_kfree_skb(skb); - - - return NETDEV_TX_OK; -} - - -/* - * Function ali_ircc_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct ali_ircc_cb *self; - unsigned long flags; - int ret = 0; - - - IRDA_ASSERT(dev != NULL, return -1;); - - self = netdev_priv(dev); - - IRDA_ASSERT(self != NULL, return -1;); - - pr_debug("%s(), %s, (cmd=0x%X)\n", __func__ , dev->name, cmd); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - pr_debug("%s(), SIOCSBANDWIDTH\n", __func__); - /* - * This function will also be used by IrLAP to change the - * speed, so we still must allow for speed change within - * interrupt context. - */ - if (!in_interrupt() && !capable(CAP_NET_ADMIN)) - return -EPERM; - - spin_lock_irqsave(&self->lock, flags); - ali_ircc_change_speed(self, irq->ifr_baudrate); - spin_unlock_irqrestore(&self->lock, flags); - break; - case SIOCSMEDIABUSY: /* Set media busy */ - pr_debug("%s(), SIOCSMEDIABUSY\n", __func__); - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - pr_debug("%s(), SIOCGRECEIVING\n", __func__); - /* This is protected */ - irq->ifr_receiving = ali_ircc_is_receiving(self); - break; - default: - ret = -EOPNOTSUPP; - } - - - return ret; -} - -/* - * Function ali_ircc_is_receiving (self) - * - * Return TRUE is we are currently receiving a frame - * - */ -static int ali_ircc_is_receiving(struct ali_ircc_cb *self) -{ - unsigned long flags; - int status = FALSE; - int iobase; - - - IRDA_ASSERT(self != NULL, return FALSE;); - - spin_lock_irqsave(&self->lock, flags); - - if (self->io.speed > 115200) - { - iobase = self->io.fir_base; - - switch_bank(iobase, BANK1); - if((inb(iobase+FIR_FIFO_FR) & 0x3f) != 0) - { - /* We are receiving something */ - pr_debug("%s(), We are receiving something\n", - __func__); - status = TRUE; - } - switch_bank(iobase, BANK0); - } - else - { - status = (self->rx_buff.state != OUTSIDE_FRAME); - } - - spin_unlock_irqrestore(&self->lock, flags); - - - return status; -} - -static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state) -{ - struct ali_ircc_cb *self = platform_get_drvdata(dev); - - net_info_ratelimited("%s, Suspending\n", ALI_IRCC_DRIVER_NAME); - - if (self->io.suspended) - return 0; - - ali_ircc_net_close(self->netdev); - - self->io.suspended = 1; - - return 0; -} - -static int ali_ircc_resume(struct platform_device *dev) -{ - struct ali_ircc_cb *self = platform_get_drvdata(dev); - - if (!self->io.suspended) - return 0; - - ali_ircc_net_open(self->netdev); - - net_info_ratelimited("%s, Waking up\n", ALI_IRCC_DRIVER_NAME); - - self->io.suspended = 0; - - return 0; -} - -/* ALi Chip Function */ - -static void SetCOMInterrupts(struct ali_ircc_cb *self , unsigned char enable) -{ - - unsigned char newMask; - - int iobase = self->io.fir_base; /* or sir_base */ - - pr_debug("%s(), -------- Start -------- ( Enable = %d )\n", - __func__, enable); - - /* Enable the interrupt which we wish to */ - if (enable){ - if (self->io.direction == IO_XMIT) - { - if (self->io.speed > 115200) /* FIR, MIR */ - { - newMask = self->ier; - } - else /* SIR */ - { - newMask = UART_IER_THRI | UART_IER_RDI; - } - } - else { - if (self->io.speed > 115200) /* FIR, MIR */ - { - newMask = self->ier; - } - else /* SIR */ - { - newMask = UART_IER_RDI; - } - } - } - else /* Disable all the interrupts */ - { - newMask = 0x00; - - } - - //SIR and FIR has different registers - if (self->io.speed > 115200) - { - switch_bank(iobase, BANK0); - outb(newMask, iobase+FIR_IER); - } - else - outb(newMask, iobase+UART_IER); - -} - -static void SIR2FIR(int iobase) -{ - //unsigned char tmp; - - - /* Already protected (change_speed() or setup()), no need to lock. - * Jean II */ - - outb(0x28, iobase+UART_MCR); - outb(0x68, iobase+UART_MCR); - outb(0x88, iobase+UART_MCR); - - outb(0x60, iobase+FIR_MCR); /* Master Reset */ - outb(0x20, iobase+FIR_MCR); /* Master Interrupt Enable */ - - //tmp = inb(iobase+FIR_LCR_B); /* SIP enable */ - //tmp |= 0x20; - //outb(tmp, iobase+FIR_LCR_B); - -} - -static void FIR2SIR(int iobase) -{ - unsigned char val; - - - /* Already protected (change_speed() or setup()), no need to lock. - * Jean II */ - - outb(0x20, iobase+FIR_MCR); /* IRQ to low */ - outb(0x00, iobase+UART_IER); - - outb(0xA0, iobase+FIR_MCR); /* Don't set master reset */ - outb(0x00, iobase+UART_FCR); - outb(0x07, iobase+UART_FCR); - - val = inb(iobase+UART_RX); - val = inb(iobase+UART_LSR); - val = inb(iobase+UART_MSR); - -} - -MODULE_AUTHOR("Benjamin Kong <benjamin_kong@ali.com.tw>"); -MODULE_DESCRIPTION("ALi FIR Controller Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" ALI_IRCC_DRIVER_NAME); - - -module_param_hw_array(io, int, ioport, NULL, 0); -MODULE_PARM_DESC(io, "Base I/O addresses"); -module_param_hw_array(irq, int, irq, NULL, 0); -MODULE_PARM_DESC(irq, "IRQ lines"); -module_param_hw_array(dma, int, dma, NULL, 0); -MODULE_PARM_DESC(dma, "DMA channels"); - -module_init(ali_ircc_init); -module_exit(ali_ircc_cleanup); diff --git a/drivers/staging/irda/drivers/ali-ircc.h b/drivers/staging/irda/drivers/ali-ircc.h deleted file mode 100644 index c2d9747a5108..000000000000 --- a/drivers/staging/irda/drivers/ali-ircc.h +++ /dev/null @@ -1,227 +0,0 @@ -/********************************************************************* - * - * Filename: ali-ircc.h - * Version: 0.5 - * Description: Driver for the ALI M1535D and M1543C FIR Controller - * Status: Experimental. - * Author: Benjamin Kong <benjamin_kong@ali.com.tw> - * Created at: 2000/10/16 03:46PM - * Modified at: 2001/1/3 02:56PM - * Modified by: Benjamin Kong <benjamin_kong@ali.com.tw> - * - * Copyright (c) 2000 Benjamin Kong <benjamin_kong@ali.com.tw> - * All Rights Reserved - * - * 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. - * - ********************************************************************/ - -#ifndef ALI_IRCC_H -#define ALI_IRCC_H - -#include <linux/ktime.h> - -#include <linux/spinlock.h> -#include <linux/pm.h> -#include <linux/types.h> -#include <asm/io.h> - -/* SIR Register */ -/* Usr definition of linux/serial_reg.h */ - -/* FIR Register */ -#define BANK0 0x20 -#define BANK1 0x21 -#define BANK2 0x22 -#define BANK3 0x23 - -#define FIR_MCR 0x07 /* Master Control Register */ - -/* Bank 0 */ -#define FIR_DR 0x00 /* Alias 0, FIR Data Register (R/W) */ -#define FIR_IER 0x01 /* Alias 1, FIR Interrupt Enable Register (R/W) */ -#define FIR_IIR 0x02 /* Alias 2, FIR Interrupt Identification Register (Read only) */ -#define FIR_LCR_A 0x03 /* Alias 3, FIR Line Control Register A (R/W) */ -#define FIR_LCR_B 0x04 /* Alias 4, FIR Line Control Register B (R/W) */ -#define FIR_LSR 0x05 /* Alias 5, FIR Line Status Register (R/W) */ -#define FIR_BSR 0x06 /* Alias 6, FIR Bus Status Register (Read only) */ - - - /* Alias 1 */ - #define IER_FIFO 0x10 /* FIR FIFO Interrupt Enable */ - #define IER_TIMER 0x20 /* Timer Interrupt Enable */ - #define IER_EOM 0x40 /* End of Message Interrupt Enable */ - #define IER_ACT 0x80 /* Active Frame Interrupt Enable */ - - /* Alias 2 */ - #define IIR_FIFO 0x10 /* FIR FIFO Interrupt */ - #define IIR_TIMER 0x20 /* Timer Interrupt */ - #define IIR_EOM 0x40 /* End of Message Interrupt */ - #define IIR_ACT 0x80 /* Active Frame Interrupt */ - - /* Alias 3 */ - #define LCR_A_FIFO_RESET 0x80 /* FIFO Reset */ - - /* Alias 4 */ - #define LCR_B_BW 0x10 /* Brick Wall */ - #define LCR_B_SIP 0x20 /* SIP Enable */ - #define LCR_B_TX_MODE 0x40 /* Transmit Mode */ - #define LCR_B_RX_MODE 0x80 /* Receive Mode */ - - /* Alias 5 */ - #define LSR_FIR_LSA 0x00 /* FIR Line Status Address */ - #define LSR_FRAME_ABORT 0x08 /* Frame Abort */ - #define LSR_CRC_ERROR 0x10 /* CRC Error */ - #define LSR_SIZE_ERROR 0x20 /* Size Error */ - #define LSR_FRAME_ERROR 0x40 /* Frame Error */ - #define LSR_FIFO_UR 0x80 /* FIFO Underrun */ - #define LSR_FIFO_OR 0x80 /* FIFO Overrun */ - - /* Alias 6 */ - #define BSR_FIFO_NOT_EMPTY 0x80 /* FIFO Not Empty */ - -/* Bank 1 */ -#define FIR_CR 0x00 /* Alias 0, FIR Configuration Register (R/W) */ -#define FIR_FIFO_TR 0x01 /* Alias 1, FIR FIFO Threshold Register (R/W) */ -#define FIR_DMA_TR 0x02 /* Alias 2, FIR DMA Threshold Register (R/W) */ -#define FIR_TIMER_IIR 0x03 /* Alias 3, FIR Timer interrupt interval register (W/O) */ -#define FIR_FIFO_FR 0x03 /* Alias 3, FIR FIFO Flag register (R/O) */ -#define FIR_FIFO_RAR 0x04 /* Alias 4, FIR FIFO Read Address register (R/O) */ -#define FIR_FIFO_WAR 0x05 /* Alias 5, FIR FIFO Write Address register (R/O) */ -#define FIR_TR 0x06 /* Alias 6, Test REgister (W/O) */ - - /* Alias 0 */ - #define CR_DMA_EN 0x01 /* DMA Enable */ - #define CR_DMA_BURST 0x02 /* DMA Burst Mode */ - #define CR_TIMER_EN 0x08 /* Timer Enable */ - - /* Alias 3 */ - #define TIMER_IIR_500 0x00 /* 500 us */ - #define TIMER_IIR_1ms 0x01 /* 1 ms */ - #define TIMER_IIR_2ms 0x02 /* 2 ms */ - #define TIMER_IIR_4ms 0x03 /* 4 ms */ - -/* Bank 2 */ -#define FIR_IRDA_CR 0x00 /* Alias 0, IrDA Control Register (R/W) */ -#define FIR_BOF_CR 0x01 /* Alias 1, BOF Count Register (R/W) */ -#define FIR_BW_CR 0x02 /* Alias 2, Brick Wall Count Register (R/W) */ -#define FIR_TX_DSR_HI 0x03 /* Alias 3, TX Data Size Register (high) (R/W) */ -#define FIR_TX_DSR_LO 0x04 /* Alias 4, TX Data Size Register (low) (R/W) */ -#define FIR_RX_DSR_HI 0x05 /* Alias 5, RX Data Size Register (high) (R/W) */ -#define FIR_RX_DSR_LO 0x06 /* Alias 6, RX Data Size Register (low) (R/W) */ - - /* Alias 0 */ - #define IRDA_CR_HDLC1152 0x80 /* 1.152Mbps HDLC Select */ - #define IRDA_CR_CRC 0X40 /* CRC Select. */ - #define IRDA_CR_HDLC 0x20 /* HDLC select. */ - #define IRDA_CR_HP_MODE 0x10 /* HP mode (read only) */ - #define IRDA_CR_SD_ST 0x08 /* SD/MODE State. */ - #define IRDA_CR_FIR_SIN 0x04 /* FIR SIN Select. */ - #define IRDA_CR_ITTX_0 0x02 /* SOUT State. IRTX force to 0 */ - #define IRDA_CR_ITTX_1 0x03 /* SOUT State. IRTX force to 1 */ - -/* Bank 3 */ -#define FIR_ID_VR 0x00 /* Alias 0, FIR ID Version Register (R/O) */ -#define FIR_MODULE_CR 0x01 /* Alias 1, FIR Module Control Register (R/W) */ -#define FIR_IO_BASE_HI 0x02 /* Alias 2, FIR Higher I/O Base Address Register (R/O) */ -#define FIR_IO_BASE_LO 0x03 /* Alias 3, FIR Lower I/O Base Address Register (R/O) */ -#define FIR_IRQ_CR 0x04 /* Alias 4, FIR IRQ Channel Register (R/O) */ -#define FIR_DMA_CR 0x05 /* Alias 5, FIR DMA Channel Register (R/O) */ - -struct ali_chip { - char *name; - int cfg[2]; - unsigned char entr1; - unsigned char entr2; - unsigned char cid_index; - unsigned char cid_value; - int (*probe)(struct ali_chip *chip, chipio_t *info); - int (*init)(struct ali_chip *chip, chipio_t *info); -}; -typedef struct ali_chip ali_chip_t; - - -/* DMA modes needed */ -#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ -#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ - -#define MAX_TX_WINDOW 7 -#define MAX_RX_WINDOW 7 - -#define TX_FIFO_Threshold 8 -#define RX_FIFO_Threshold 1 -#define TX_DMA_Threshold 1 -#define RX_DMA_Threshold 1 - -/* For storing entries in the status FIFO */ - -struct st_fifo_entry { - int status; - int len; -}; - -struct st_fifo { - struct st_fifo_entry entries[MAX_RX_WINDOW]; - int pending_bytes; - int head; - int tail; - int len; -}; - -struct frame_cb { - void *start; /* Start of frame in DMA mem */ - int len; /* Length of frame in DMA mem */ -}; - -struct tx_fifo { - struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */ - int ptr; /* Currently being sent */ - int len; /* Length of queue */ - int free; /* Next free slot */ - void *tail; /* Next free start in DMA mem */ -}; - -/* Private data for each instance */ -struct ali_ircc_cb { - - struct st_fifo st_fifo; /* Info about received frames */ - struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ - - struct net_device *netdev; /* Yes! we are some kind of netdevice */ - - struct irlap_cb *irlap; /* The link layer we are binded to */ - struct qos_info qos; /* QoS capabilities for this device */ - - chipio_t io; /* IrDA controller information */ - iobuff_t tx_buff; /* Transmit buffer */ - iobuff_t rx_buff; /* Receive buffer */ - dma_addr_t tx_buff_dma; - dma_addr_t rx_buff_dma; - - __u8 ier; /* Interrupt enable register */ - - __u8 InterruptID; /* Interrupt ID */ - __u8 BusStatus; /* Bus Status */ - __u8 LineStatus; /* Line Status */ - - unsigned char rcvFramesOverflow; - - ktime_t stamp; - - spinlock_t lock; /* For serializing operations */ - - __u32 new_speed; - int index; /* Instance index */ - - unsigned char fifo_opti_buf; -}; - -static inline void switch_bank(int iobase, int bank) -{ - outb(bank, iobase+FIR_MCR); -} - -#endif /* ALI_IRCC_H */ diff --git a/drivers/staging/irda/drivers/au1k_ir.c b/drivers/staging/irda/drivers/au1k_ir.c deleted file mode 100644 index 73e3e4b041bf..000000000000 --- a/drivers/staging/irda/drivers/au1k_ir.c +++ /dev/null @@ -1,985 +0,0 @@ -/* - * Alchemy Semi Au1000 IrDA driver - * - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ppopov@mvista.com or source@mvista.com - * - * This program is free software; you can distribute it and/or modify it - * under the terms 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; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <linux/clk.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/types.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> -#include <net/irda/wrapper.h> -#include <net/irda/irda_device.h> -#include <asm/mach-au1x00/au1000.h> - -/* registers */ -#define IR_RING_PTR_STATUS 0x00 -#define IR_RING_BASE_ADDR_H 0x04 -#define IR_RING_BASE_ADDR_L 0x08 -#define IR_RING_SIZE 0x0C -#define IR_RING_PROMPT 0x10 -#define IR_RING_ADDR_CMPR 0x14 -#define IR_INT_CLEAR 0x18 -#define IR_CONFIG_1 0x20 -#define IR_SIR_FLAGS 0x24 -#define IR_STATUS 0x28 -#define IR_READ_PHY_CONFIG 0x2C -#define IR_WRITE_PHY_CONFIG 0x30 -#define IR_MAX_PKT_LEN 0x34 -#define IR_RX_BYTE_CNT 0x38 -#define IR_CONFIG_2 0x3C -#define IR_ENABLE 0x40 - -/* Config1 */ -#define IR_RX_INVERT_LED (1 << 0) -#define IR_TX_INVERT_LED (1 << 1) -#define IR_ST (1 << 2) -#define IR_SF (1 << 3) -#define IR_SIR (1 << 4) -#define IR_MIR (1 << 5) -#define IR_FIR (1 << 6) -#define IR_16CRC (1 << 7) -#define IR_TD (1 << 8) -#define IR_RX_ALL (1 << 9) -#define IR_DMA_ENABLE (1 << 10) -#define IR_RX_ENABLE (1 << 11) -#define IR_TX_ENABLE (1 << 12) -#define IR_LOOPBACK (1 << 14) -#define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \ - IR_RX_ALL | IR_RX_ENABLE | IR_SF | \ - IR_16CRC) - -/* ir_status */ -#define IR_RX_STATUS (1 << 9) -#define IR_TX_STATUS (1 << 10) -#define IR_PHYEN (1 << 15) - -/* ir_write_phy_config */ -#define IR_BR(x) (((x) & 0x3f) << 10) /* baud rate */ -#define IR_PW(x) (((x) & 0x1f) << 5) /* pulse width */ -#define IR_P(x) ((x) & 0x1f) /* preamble bits */ - -/* Config2 */ -#define IR_MODE_INV (1 << 0) -#define IR_ONE_PIN (1 << 1) -#define IR_PHYCLK_40MHZ (0 << 2) -#define IR_PHYCLK_48MHZ (1 << 2) -#define IR_PHYCLK_56MHZ (2 << 2) -#define IR_PHYCLK_64MHZ (3 << 2) -#define IR_DP (1 << 4) -#define IR_DA (1 << 5) -#define IR_FLT_HIGH (0 << 6) -#define IR_FLT_MEDHI (1 << 6) -#define IR_FLT_MEDLO (2 << 6) -#define IR_FLT_LO (3 << 6) -#define IR_IEN (1 << 8) - -/* ir_enable */ -#define IR_HC (1 << 3) /* divide SBUS clock by 2 */ -#define IR_CE (1 << 2) /* clock enable */ -#define IR_C (1 << 1) /* coherency bit */ -#define IR_BE (1 << 0) /* set in big endian mode */ - -#define NUM_IR_DESC 64 -#define RING_SIZE_4 0x0 -#define RING_SIZE_16 0x3 -#define RING_SIZE_64 0xF -#define MAX_NUM_IR_DESC 64 -#define MAX_BUF_SIZE 2048 - -/* Ring descriptor flags */ -#define AU_OWN (1 << 7) /* tx,rx */ -#define IR_DIS_CRC (1 << 6) /* tx */ -#define IR_BAD_CRC (1 << 5) /* tx */ -#define IR_NEED_PULSE (1 << 4) /* tx */ -#define IR_FORCE_UNDER (1 << 3) /* tx */ -#define IR_DISABLE_TX (1 << 2) /* tx */ -#define IR_HW_UNDER (1 << 0) /* tx */ -#define IR_TX_ERROR (IR_DIS_CRC | IR_BAD_CRC | IR_HW_UNDER) - -#define IR_PHY_ERROR (1 << 6) /* rx */ -#define IR_CRC_ERROR (1 << 5) /* rx */ -#define IR_MAX_LEN (1 << 4) /* rx */ -#define IR_FIFO_OVER (1 << 3) /* rx */ -#define IR_SIR_ERROR (1 << 2) /* rx */ -#define IR_RX_ERROR (IR_PHY_ERROR | IR_CRC_ERROR | \ - IR_MAX_LEN | IR_FIFO_OVER | IR_SIR_ERROR) - -struct db_dest { - struct db_dest *pnext; - volatile u32 *vaddr; - dma_addr_t dma_addr; -}; - -struct ring_dest { - u8 count_0; /* 7:0 */ - u8 count_1; /* 12:8 */ - u8 reserved; - u8 flags; - u8 addr_0; /* 7:0 */ - u8 addr_1; /* 15:8 */ - u8 addr_2; /* 23:16 */ - u8 addr_3; /* 31:24 */ -}; - -/* Private data for each instance */ -struct au1k_private { - void __iomem *iobase; - int irq_rx, irq_tx; - - struct db_dest *pDBfree; - struct db_dest db[2 * NUM_IR_DESC]; - volatile struct ring_dest *rx_ring[NUM_IR_DESC]; - volatile struct ring_dest *tx_ring[NUM_IR_DESC]; - struct db_dest *rx_db_inuse[NUM_IR_DESC]; - struct db_dest *tx_db_inuse[NUM_IR_DESC]; - u32 rx_head; - u32 tx_head; - u32 tx_tail; - u32 tx_full; - - iobuff_t rx_buff; - - struct net_device *netdev; - struct qos_info qos; - struct irlap_cb *irlap; - - u8 open; - u32 speed; - u32 newspeed; - - struct resource *ioarea; - struct au1k_irda_platform_data *platdata; - struct clk *irda_clk; -}; - -static int qos_mtt_bits = 0x07; /* 1 ms or more */ - -static void au1k_irda_plat_set_phy_mode(struct au1k_private *p, int mode) -{ - if (p->platdata && p->platdata->set_phy_mode) - p->platdata->set_phy_mode(mode); -} - -static inline unsigned long irda_read(struct au1k_private *p, - unsigned long ofs) -{ - /* - * IrDA peripheral bug. You have to read the register - * twice to get the right value. - */ - (void)__raw_readl(p->iobase + ofs); - return __raw_readl(p->iobase + ofs); -} - -static inline void irda_write(struct au1k_private *p, unsigned long ofs, - unsigned long val) -{ - __raw_writel(val, p->iobase + ofs); - wmb(); -} - -/* - * Buffer allocation/deallocation routines. The buffer descriptor returned - * has the virtual and dma address of a buffer suitable for - * both, receive and transmit operations. - */ -static struct db_dest *GetFreeDB(struct au1k_private *aup) -{ - struct db_dest *db; - db = aup->pDBfree; - - if (db) - aup->pDBfree = db->pnext; - return db; -} - -/* - DMA memory allocation, derived from pci_alloc_consistent. - However, the Au1000 data cache is coherent (when programmed - so), therefore we return KSEG0 address, not KSEG1. -*/ -static void *dma_alloc(size_t size, dma_addr_t *dma_handle) -{ - void *ret; - int gfp = GFP_ATOMIC | GFP_DMA; - - ret = (void *)__get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - ret = (void *)KSEG0ADDR(ret); - } - return ret; -} - -static void dma_free(void *vaddr, size_t size) -{ - vaddr = (void *)KSEG0ADDR(vaddr); - free_pages((unsigned long) vaddr, get_order(size)); -} - - -static void setup_hw_rings(struct au1k_private *aup, u32 rx_base, u32 tx_base) -{ - int i; - for (i = 0; i < NUM_IR_DESC; i++) { - aup->rx_ring[i] = (volatile struct ring_dest *) - (rx_base + sizeof(struct ring_dest) * i); - } - for (i = 0; i < NUM_IR_DESC; i++) { - aup->tx_ring[i] = (volatile struct ring_dest *) - (tx_base + sizeof(struct ring_dest) * i); - } -} - -static int au1k_irda_init_iobuf(iobuff_t *io, int size) -{ - io->head = kmalloc(size, GFP_KERNEL); - if (io->head != NULL) { - io->truesize = size; - io->in_frame = FALSE; - io->state = OUTSIDE_FRAME; - io->data = io->head; - } - return io->head ? 0 : -ENOMEM; -} - -/* - * Set the IrDA communications speed. - */ -static int au1k_irda_set_speed(struct net_device *dev, int speed) -{ - struct au1k_private *aup = netdev_priv(dev); - volatile struct ring_dest *ptxd; - unsigned long control; - int ret = 0, timeout = 10, i; - - if (speed == aup->speed) - return ret; - - /* disable PHY first */ - au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); - irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); - - /* disable RX/TX */ - irda_write(aup, IR_CONFIG_1, - irda_read(aup, IR_CONFIG_1) & ~(IR_RX_ENABLE | IR_TX_ENABLE)); - msleep(20); - while (irda_read(aup, IR_STATUS) & (IR_RX_STATUS | IR_TX_STATUS)) { - msleep(20); - if (!timeout--) { - netdev_err(dev, "rx/tx disable timeout\n"); - break; - } - } - - /* disable DMA */ - irda_write(aup, IR_CONFIG_1, - irda_read(aup, IR_CONFIG_1) & ~IR_DMA_ENABLE); - msleep(20); - - /* After we disable tx/rx. the index pointers go back to zero. */ - aup->tx_head = aup->tx_tail = aup->rx_head = 0; - for (i = 0; i < NUM_IR_DESC; i++) { - ptxd = aup->tx_ring[i]; - ptxd->flags = 0; - ptxd->count_0 = 0; - ptxd->count_1 = 0; - } - - for (i = 0; i < NUM_IR_DESC; i++) { - ptxd = aup->rx_ring[i]; - ptxd->count_0 = 0; - ptxd->count_1 = 0; - ptxd->flags = AU_OWN; - } - - if (speed == 4000000) - au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_FIR); - else - au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); - - switch (speed) { - case 9600: - irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(11) | IR_PW(12)); - irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); - break; - case 19200: - irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(5) | IR_PW(12)); - irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); - break; - case 38400: - irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(2) | IR_PW(12)); - irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); - break; - case 57600: - irda_write(aup, IR_WRITE_PHY_CONFIG, IR_BR(1) | IR_PW(12)); - irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); - break; - case 115200: - irda_write(aup, IR_WRITE_PHY_CONFIG, IR_PW(12)); - irda_write(aup, IR_CONFIG_1, IR_SIR_MODE); - break; - case 4000000: - irda_write(aup, IR_WRITE_PHY_CONFIG, IR_P(15)); - irda_write(aup, IR_CONFIG_1, IR_FIR | IR_DMA_ENABLE | - IR_RX_ENABLE); - break; - default: - netdev_err(dev, "unsupported speed %x\n", speed); - ret = -EINVAL; - break; - } - - aup->speed = speed; - irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) | IR_PHYEN); - - control = irda_read(aup, IR_STATUS); - irda_write(aup, IR_RING_PROMPT, 0); - - if (control & (1 << 14)) { - netdev_err(dev, "configuration error\n"); - } else { - if (control & (1 << 11)) - netdev_debug(dev, "Valid SIR config\n"); - if (control & (1 << 12)) - netdev_debug(dev, "Valid MIR config\n"); - if (control & (1 << 13)) - netdev_debug(dev, "Valid FIR config\n"); - if (control & (1 << 10)) - netdev_debug(dev, "TX enabled\n"); - if (control & (1 << 9)) - netdev_debug(dev, "RX enabled\n"); - } - - return ret; -} - -static void update_rx_stats(struct net_device *dev, u32 status, u32 count) -{ - struct net_device_stats *ps = &dev->stats; - - ps->rx_packets++; - - if (status & IR_RX_ERROR) { - ps->rx_errors++; - if (status & (IR_PHY_ERROR | IR_FIFO_OVER)) - ps->rx_missed_errors++; - if (status & IR_MAX_LEN) - ps->rx_length_errors++; - if (status & IR_CRC_ERROR) - ps->rx_crc_errors++; - } else - ps->rx_bytes += count; -} - -static void update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) -{ - struct net_device_stats *ps = &dev->stats; - - ps->tx_packets++; - ps->tx_bytes += pkt_len; - - if (status & IR_TX_ERROR) { - ps->tx_errors++; - ps->tx_aborted_errors++; - } -} - -static void au1k_tx_ack(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - volatile struct ring_dest *ptxd; - - ptxd = aup->tx_ring[aup->tx_tail]; - while (!(ptxd->flags & AU_OWN) && (aup->tx_tail != aup->tx_head)) { - update_tx_stats(dev, ptxd->flags, - (ptxd->count_1 << 8) | ptxd->count_0); - ptxd->count_0 = 0; - ptxd->count_1 = 0; - wmb(); - aup->tx_tail = (aup->tx_tail + 1) & (NUM_IR_DESC - 1); - ptxd = aup->tx_ring[aup->tx_tail]; - - if (aup->tx_full) { - aup->tx_full = 0; - netif_wake_queue(dev); - } - } - - if (aup->tx_tail == aup->tx_head) { - if (aup->newspeed) { - au1k_irda_set_speed(dev, aup->newspeed); - aup->newspeed = 0; - } else { - irda_write(aup, IR_CONFIG_1, - irda_read(aup, IR_CONFIG_1) & ~IR_TX_ENABLE); - irda_write(aup, IR_CONFIG_1, - irda_read(aup, IR_CONFIG_1) | IR_RX_ENABLE); - irda_write(aup, IR_RING_PROMPT, 0); - } - } -} - -static int au1k_irda_rx(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - volatile struct ring_dest *prxd; - struct sk_buff *skb; - struct db_dest *pDB; - u32 flags, count; - - prxd = aup->rx_ring[aup->rx_head]; - flags = prxd->flags; - - while (!(flags & AU_OWN)) { - pDB = aup->rx_db_inuse[aup->rx_head]; - count = (prxd->count_1 << 8) | prxd->count_0; - if (!(flags & IR_RX_ERROR)) { - /* good frame */ - update_rx_stats(dev, flags, count); - skb = alloc_skb(count + 1, GFP_ATOMIC); - if (skb == NULL) { - dev->stats.rx_dropped++; - continue; - } - skb_reserve(skb, 1); - if (aup->speed == 4000000) - skb_put(skb, count); - else - skb_put(skb, count - 2); - skb_copy_to_linear_data(skb, (void *)pDB->vaddr, - count - 2); - skb->dev = dev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - prxd->count_0 = 0; - prxd->count_1 = 0; - } - prxd->flags |= AU_OWN; - aup->rx_head = (aup->rx_head + 1) & (NUM_IR_DESC - 1); - irda_write(aup, IR_RING_PROMPT, 0); - - /* next descriptor */ - prxd = aup->rx_ring[aup->rx_head]; - flags = prxd->flags; - - } - return 0; -} - -static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id) -{ - struct net_device *dev = dev_id; - struct au1k_private *aup = netdev_priv(dev); - - irda_write(aup, IR_INT_CLEAR, 0); /* ack irda interrupts */ - - au1k_irda_rx(dev); - au1k_tx_ack(dev); - - return IRQ_HANDLED; -} - -static int au1k_init(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - u32 enable, ring_address, phyck; - struct clk *c; - int i; - - c = clk_get(NULL, "irda_clk"); - if (IS_ERR(c)) - return PTR_ERR(c); - i = clk_prepare_enable(c); - if (i) { - clk_put(c); - return i; - } - - switch (clk_get_rate(c)) { - case 40000000: - phyck = IR_PHYCLK_40MHZ; - break; - case 48000000: - phyck = IR_PHYCLK_48MHZ; - break; - case 56000000: - phyck = IR_PHYCLK_56MHZ; - break; - case 64000000: - phyck = IR_PHYCLK_64MHZ; - break; - default: - clk_disable_unprepare(c); - clk_put(c); - return -EINVAL; - } - aup->irda_clk = c; - - enable = IR_HC | IR_CE | IR_C; -#ifndef CONFIG_CPU_LITTLE_ENDIAN - enable |= IR_BE; -#endif - aup->tx_head = 0; - aup->tx_tail = 0; - aup->rx_head = 0; - - for (i = 0; i < NUM_IR_DESC; i++) - aup->rx_ring[i]->flags = AU_OWN; - - irda_write(aup, IR_ENABLE, enable); - msleep(20); - - /* disable PHY */ - au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); - irda_write(aup, IR_STATUS, irda_read(aup, IR_STATUS) & ~IR_PHYEN); - msleep(20); - - irda_write(aup, IR_MAX_PKT_LEN, MAX_BUF_SIZE); - - ring_address = (u32)virt_to_phys((void *)aup->rx_ring[0]); - irda_write(aup, IR_RING_BASE_ADDR_H, ring_address >> 26); - irda_write(aup, IR_RING_BASE_ADDR_L, (ring_address >> 10) & 0xffff); - - irda_write(aup, IR_RING_SIZE, - (RING_SIZE_64 << 8) | (RING_SIZE_64 << 12)); - - irda_write(aup, IR_CONFIG_2, phyck | IR_ONE_PIN); - irda_write(aup, IR_RING_ADDR_CMPR, 0); - - au1k_irda_set_speed(dev, 9600); - return 0; -} - -static int au1k_irda_start(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - char hwname[32]; - int retval; - - retval = au1k_init(dev); - if (retval) { - netdev_err(dev, "error in au1k_init\n"); - return retval; - } - - retval = request_irq(aup->irq_tx, &au1k_irda_interrupt, 0, - dev->name, dev); - if (retval) { - netdev_err(dev, "unable to get IRQ %d\n", dev->irq); - return retval; - } - retval = request_irq(aup->irq_rx, &au1k_irda_interrupt, 0, - dev->name, dev); - if (retval) { - free_irq(aup->irq_tx, dev); - netdev_err(dev, "unable to get IRQ %d\n", dev->irq); - return retval; - } - - /* Give self a hardware name */ - sprintf(hwname, "Au1000 SIR/FIR"); - aup->irlap = irlap_open(dev, &aup->qos, hwname); - netif_start_queue(dev); - - /* int enable */ - irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) | IR_IEN); - - /* power up */ - au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_SIR); - - return 0; -} - -static int au1k_irda_stop(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - - au1k_irda_plat_set_phy_mode(aup, AU1000_IRDA_PHY_MODE_OFF); - - /* disable interrupts */ - irda_write(aup, IR_CONFIG_2, irda_read(aup, IR_CONFIG_2) & ~IR_IEN); - irda_write(aup, IR_CONFIG_1, 0); - irda_write(aup, IR_ENABLE, 0); /* disable clock */ - - if (aup->irlap) { - irlap_close(aup->irlap); - aup->irlap = NULL; - } - - netif_stop_queue(dev); - - /* disable the interrupt */ - free_irq(aup->irq_tx, dev); - free_irq(aup->irq_rx, dev); - - clk_disable_unprepare(aup->irda_clk); - clk_put(aup->irda_clk); - - return 0; -} - -/* - * Au1000 transmit routine. - */ -static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - int speed = irda_get_next_speed(skb); - volatile struct ring_dest *ptxd; - struct db_dest *pDB; - u32 len, flags; - - if (speed != aup->speed && speed != -1) - aup->newspeed = speed; - - if ((skb->len == 0) && (aup->newspeed)) { - if (aup->tx_tail == aup->tx_head) { - au1k_irda_set_speed(dev, speed); - aup->newspeed = 0; - } - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - ptxd = aup->tx_ring[aup->tx_head]; - flags = ptxd->flags; - - if (flags & AU_OWN) { - netdev_debug(dev, "tx_full\n"); - netif_stop_queue(dev); - aup->tx_full = 1; - return 1; - } else if (((aup->tx_head + 1) & (NUM_IR_DESC - 1)) == aup->tx_tail) { - netdev_debug(dev, "tx_full\n"); - netif_stop_queue(dev); - aup->tx_full = 1; - return 1; - } - - pDB = aup->tx_db_inuse[aup->tx_head]; - -#if 0 - if (irda_read(aup, IR_RX_BYTE_CNT) != 0) { - netdev_debug(dev, "tx warning: rx byte cnt %x\n", - irda_read(aup, IR_RX_BYTE_CNT)); - } -#endif - - if (aup->speed == 4000000) { - /* FIR */ - skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len); - ptxd->count_0 = skb->len & 0xff; - ptxd->count_1 = (skb->len >> 8) & 0xff; - } else { - /* SIR */ - len = async_wrap_skb(skb, (u8 *)pDB->vaddr, MAX_BUF_SIZE); - ptxd->count_0 = len & 0xff; - ptxd->count_1 = (len >> 8) & 0xff; - ptxd->flags |= IR_DIS_CRC; - } - ptxd->flags |= AU_OWN; - wmb(); - - irda_write(aup, IR_CONFIG_1, - irda_read(aup, IR_CONFIG_1) | IR_TX_ENABLE); - irda_write(aup, IR_RING_PROMPT, 0); - - dev_kfree_skb(skb); - aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1); - return NETDEV_TX_OK; -} - -/* - * The Tx ring has been full longer than the watchdog timeout - * value. The transmitter must be hung? - */ -static void au1k_tx_timeout(struct net_device *dev) -{ - u32 speed; - struct au1k_private *aup = netdev_priv(dev); - - netdev_err(dev, "tx timeout\n"); - speed = aup->speed; - aup->speed = 0; - au1k_irda_set_speed(dev, speed); - aup->tx_full = 0; - netif_wake_queue(dev); -} - -static int au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) -{ - struct if_irda_req *rq = (struct if_irda_req *)ifreq; - struct au1k_private *aup = netdev_priv(dev); - int ret = -EOPNOTSUPP; - - switch (cmd) { - case SIOCSBANDWIDTH: - if (capable(CAP_NET_ADMIN)) { - /* - * We are unable to set the speed if the - * device is not running. - */ - if (aup->open) - ret = au1k_irda_set_speed(dev, - rq->ifr_baudrate); - else { - netdev_err(dev, "ioctl: !netif_running\n"); - ret = 0; - } - } - break; - - case SIOCSMEDIABUSY: - ret = -EPERM; - if (capable(CAP_NET_ADMIN)) { - irda_device_set_media_busy(dev, TRUE); - ret = 0; - } - break; - - case SIOCGRECEIVING: - rq->ifr_receiving = 0; - break; - default: - break; - } - return ret; -} - -static const struct net_device_ops au1k_irda_netdev_ops = { - .ndo_open = au1k_irda_start, - .ndo_stop = au1k_irda_stop, - .ndo_start_xmit = au1k_irda_hard_xmit, - .ndo_tx_timeout = au1k_tx_timeout, - .ndo_do_ioctl = au1k_irda_ioctl, -}; - -static int au1k_irda_net_init(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - struct db_dest *pDB, *pDBfree; - int i, err, retval = 0; - dma_addr_t temp; - - err = au1k_irda_init_iobuf(&aup->rx_buff, 14384); - if (err) - goto out1; - - dev->netdev_ops = &au1k_irda_netdev_ops; - - irda_init_max_qos_capabilies(&aup->qos); - - /* The only value we must override it the baudrate */ - aup->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 | - IR_57600 | IR_115200 | IR_576000 | (IR_4000000 << 8); - - aup->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&aup->qos); - - retval = -ENOMEM; - - /* Tx ring follows rx ring + 512 bytes */ - /* we need a 1k aligned buffer */ - aup->rx_ring[0] = (struct ring_dest *) - dma_alloc(2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest)), - &temp); - if (!aup->rx_ring[0]) - goto out2; - - /* allocate the data buffers */ - aup->db[0].vaddr = - dma_alloc(MAX_BUF_SIZE * 2 * NUM_IR_DESC, &temp); - if (!aup->db[0].vaddr) - goto out3; - - setup_hw_rings(aup, (u32)aup->rx_ring[0], (u32)aup->rx_ring[0] + 512); - - pDBfree = NULL; - pDB = aup->db; - for (i = 0; i < (2 * NUM_IR_DESC); i++) { - pDB->pnext = pDBfree; - pDBfree = pDB; - pDB->vaddr = - (u32 *)((unsigned)aup->db[0].vaddr + (MAX_BUF_SIZE * i)); - pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr); - pDB++; - } - aup->pDBfree = pDBfree; - - /* attach a data buffer to each descriptor */ - for (i = 0; i < NUM_IR_DESC; i++) { - pDB = GetFreeDB(aup); - if (!pDB) - goto out3; - aup->rx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); - aup->rx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); - aup->rx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); - aup->rx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); - aup->rx_db_inuse[i] = pDB; - } - for (i = 0; i < NUM_IR_DESC; i++) { - pDB = GetFreeDB(aup); - if (!pDB) - goto out3; - aup->tx_ring[i]->addr_0 = (u8)(pDB->dma_addr & 0xff); - aup->tx_ring[i]->addr_1 = (u8)((pDB->dma_addr >> 8) & 0xff); - aup->tx_ring[i]->addr_2 = (u8)((pDB->dma_addr >> 16) & 0xff); - aup->tx_ring[i]->addr_3 = (u8)((pDB->dma_addr >> 24) & 0xff); - aup->tx_ring[i]->count_0 = 0; - aup->tx_ring[i]->count_1 = 0; - aup->tx_ring[i]->flags = 0; - aup->tx_db_inuse[i] = pDB; - } - - return 0; - -out3: - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); -out2: - kfree(aup->rx_buff.head); -out1: - netdev_err(dev, "au1k_irda_net_init() failed. Returns %d\n"); - return retval; -} - -static int au1k_irda_probe(struct platform_device *pdev) -{ - struct au1k_private *aup; - struct net_device *dev; - struct resource *r; - struct clk *c; - int err; - - dev = alloc_irdadev(sizeof(struct au1k_private)); - if (!dev) - return -ENOMEM; - - aup = netdev_priv(dev); - - aup->platdata = pdev->dev.platform_data; - - err = -EINVAL; - r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!r) - goto out; - - aup->irq_tx = r->start; - - r = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!r) - goto out; - - aup->irq_rx = r->start; - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - goto out; - - err = -EBUSY; - aup->ioarea = request_mem_region(r->start, resource_size(r), - pdev->name); - if (!aup->ioarea) - goto out; - - /* bail out early if clock doesn't exist */ - c = clk_get(NULL, "irda_clk"); - if (IS_ERR(c)) { - err = PTR_ERR(c); - goto out; - } - clk_put(c); - - aup->iobase = ioremap_nocache(r->start, resource_size(r)); - if (!aup->iobase) - goto out2; - - dev->irq = aup->irq_rx; - - err = au1k_irda_net_init(dev); - if (err) - goto out3; - err = register_netdev(dev); - if (err) - goto out4; - - platform_set_drvdata(pdev, dev); - - netdev_info(dev, "IrDA: Registered device\n"); - return 0; - -out4: - dma_free((void *)aup->db[0].vaddr, - MAX_BUF_SIZE * 2 * NUM_IR_DESC); - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); - kfree(aup->rx_buff.head); -out3: - iounmap(aup->iobase); -out2: - release_resource(aup->ioarea); - kfree(aup->ioarea); -out: - free_netdev(dev); - return err; -} - -static int au1k_irda_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct au1k_private *aup = netdev_priv(dev); - - unregister_netdev(dev); - - dma_free((void *)aup->db[0].vaddr, - MAX_BUF_SIZE * 2 * NUM_IR_DESC); - dma_free((void *)aup->rx_ring[0], - 2 * MAX_NUM_IR_DESC * (sizeof(struct ring_dest))); - kfree(aup->rx_buff.head); - - iounmap(aup->iobase); - release_resource(aup->ioarea); - kfree(aup->ioarea); - - free_netdev(dev); - - return 0; -} - -static struct platform_driver au1k_irda_driver = { - .driver = { - .name = "au1000-irda", - }, - .probe = au1k_irda_probe, - .remove = au1k_irda_remove, -}; - -module_platform_driver(au1k_irda_driver); - -MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>"); -MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); diff --git a/drivers/staging/irda/drivers/bfin_sir.c b/drivers/staging/irda/drivers/bfin_sir.c deleted file mode 100644 index 59e409b68349..000000000000 --- a/drivers/staging/irda/drivers/bfin_sir.c +++ /dev/null @@ -1,819 +0,0 @@ -/* - * Blackfin Infra-red Driver - * - * Copyright 2006-2009 Analog Devices Inc. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - * - */ -#include "bfin_sir.h" - -#ifdef CONFIG_SIR_BFIN_DMA -#define DMA_SIR_RX_XCNT 10 -#define DMA_SIR_RX_YCNT (PAGE_SIZE / DMA_SIR_RX_XCNT) -#define DMA_SIR_RX_FLUSH_JIFS (HZ * 4 / 250) -#endif - -#if ANOMALY_05000447 -static int max_rate = 57600; -#else -static int max_rate = 115200; -#endif - -static void bfin_sir_rx_dma_timeout(struct timer_list *t); - -static void turnaround_delay(int mtt) -{ - long ticks; - - mtt = mtt < 10000 ? 10000 : mtt; - ticks = 1 + mtt / (USEC_PER_SEC / HZ); - schedule_timeout_uninterruptible(ticks); -} - -static void bfin_sir_init_ports(struct bfin_sir_port *sp, struct platform_device *pdev) -{ - int i; - struct resource *res; - - for (i = 0; i < pdev->num_resources; i++) { - res = &pdev->resource[i]; - switch (res->flags) { - case IORESOURCE_MEM: - sp->membase = (void __iomem *)res->start; - break; - case IORESOURCE_IRQ: - sp->irq = res->start; - break; - case IORESOURCE_DMA: - sp->rx_dma_channel = res->start; - sp->tx_dma_channel = res->end; - break; - default: - break; - } - } - - sp->clk = get_sclk(); -#ifdef CONFIG_SIR_BFIN_DMA - sp->tx_done = 1; - timer_setup(&sp->rx_dma_timer, bfin_sir_rx_dma_timeout, 0); -#endif -} - -static void bfin_sir_stop_tx(struct bfin_sir_port *port) -{ -#ifdef CONFIG_SIR_BFIN_DMA - disable_dma(port->tx_dma_channel); -#endif - - while (!(UART_GET_LSR(port) & THRE)) { - cpu_relax(); - continue; - } - - UART_CLEAR_IER(port, ETBEI); -} - -static void bfin_sir_enable_tx(struct bfin_sir_port *port) -{ - UART_SET_IER(port, ETBEI); -} - -static void bfin_sir_stop_rx(struct bfin_sir_port *port) -{ - UART_CLEAR_IER(port, ERBFI); -} - -static void bfin_sir_enable_rx(struct bfin_sir_port *port) -{ - UART_SET_IER(port, ERBFI); -} - -static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed) -{ - int ret = -EINVAL; - unsigned int quot; - unsigned short val, lsr, lcr; - static int utime; - int count = 10; - - lcr = WLS(8); - - switch (speed) { - case 9600: - case 19200: - case 38400: - case 57600: - case 115200: - - /* - * IRDA is not affected by anomaly 05000230, so there is no - * need to tweak the divisor like he UART driver (which will - * slightly speed up the baud rate on us). - */ - quot = (port->clk + (8 * speed)) / (16 * speed); - - do { - udelay(utime); - lsr = UART_GET_LSR(port); - } while (!(lsr & TEMT) && count--); - - /* The useconds for 1 bits to transmit */ - utime = 1000000 / speed + 1; - - /* Clear UCEN bit to reset the UART state machine - * and control registers - */ - val = UART_GET_GCTL(port); - val &= ~UCEN; - UART_PUT_GCTL(port, val); - - /* Set DLAB in LCR to Access THR RBR IER */ - UART_SET_DLAB(port); - SSYNC(); - - UART_PUT_DLL(port, quot & 0xFF); - UART_PUT_DLH(port, (quot >> 8) & 0xFF); - SSYNC(); - - /* Clear DLAB in LCR */ - UART_CLEAR_DLAB(port); - SSYNC(); - - UART_PUT_LCR(port, lcr); - - val = UART_GET_GCTL(port); - val |= UCEN; - UART_PUT_GCTL(port, val); - - ret = 0; - break; - default: - printk(KERN_WARNING "bfin_sir: Invalid speed %d\n", speed); - break; - } - - val = UART_GET_GCTL(port); - /* If not add the 'RPOLC', we can't catch the receive interrupt. - * It's related with the HW layout and the IR transiver. - */ - val |= UMOD_IRDA | RPOLC; - UART_PUT_GCTL(port, val); - return ret; -} - -static int bfin_sir_is_receiving(struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - - if (!(UART_GET_IER(port) & ERBFI)) - return 0; - return self->rx_buff.state != OUTSIDE_FRAME; -} - -#ifdef CONFIG_SIR_BFIN_PIO -static void bfin_sir_tx_chars(struct net_device *dev) -{ - unsigned int chr; - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - - if (self->tx_buff.len != 0) { - chr = *(self->tx_buff.data); - UART_PUT_CHAR(port, chr); - self->tx_buff.data++; - self->tx_buff.len--; - } else { - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.data - self->tx_buff.head; - if (self->newspeed) { - bfin_sir_set_speed(port, self->newspeed); - self->speed = self->newspeed; - self->newspeed = 0; - } - bfin_sir_stop_tx(port); - bfin_sir_enable_rx(port); - /* I'm hungry! */ - netif_wake_queue(dev); - } -} - -static void bfin_sir_rx_chars(struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - unsigned char ch; - - UART_CLEAR_LSR(port); - ch = UART_GET_CHAR(port); - async_unwrap_char(dev, &self->stats, &self->rx_buff, ch); -} - -static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - - spin_lock(&self->lock); - while ((UART_GET_LSR(port) & DR)) - bfin_sir_rx_chars(dev); - spin_unlock(&self->lock); - - return IRQ_HANDLED; -} - -static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - - spin_lock(&self->lock); - if (UART_GET_LSR(port) & THRE) - bfin_sir_tx_chars(dev); - spin_unlock(&self->lock); - - return IRQ_HANDLED; -} -#endif /* CONFIG_SIR_BFIN_PIO */ - -#ifdef CONFIG_SIR_BFIN_DMA -static void bfin_sir_dma_tx_chars(struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - - if (!port->tx_done) - return; - port->tx_done = 0; - - if (self->tx_buff.len == 0) { - self->stats.tx_packets++; - if (self->newspeed) { - bfin_sir_set_speed(port, self->newspeed); - self->speed = self->newspeed; - self->newspeed = 0; - } - bfin_sir_enable_rx(port); - port->tx_done = 1; - netif_wake_queue(dev); - return; - } - - blackfin_dcache_flush_range((unsigned long)(self->tx_buff.data), - (unsigned long)(self->tx_buff.data+self->tx_buff.len)); - set_dma_config(port->tx_dma_channel, - set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, - INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8, - DMA_SYNC_RESTART)); - set_dma_start_addr(port->tx_dma_channel, - (unsigned long)(self->tx_buff.data)); - set_dma_x_count(port->tx_dma_channel, self->tx_buff.len); - set_dma_x_modify(port->tx_dma_channel, 1); - enable_dma(port->tx_dma_channel); -} - -static irqreturn_t bfin_sir_dma_tx_int(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - - spin_lock(&self->lock); - if (!(get_dma_curr_irqstat(port->tx_dma_channel) & DMA_RUN)) { - clear_dma_irqstat(port->tx_dma_channel); - bfin_sir_stop_tx(port); - - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; - self->tx_buff.len = 0; - if (self->newspeed) { - bfin_sir_set_speed(port, self->newspeed); - self->speed = self->newspeed; - self->newspeed = 0; - } - bfin_sir_enable_rx(port); - /* I'm hungry! */ - netif_wake_queue(dev); - port->tx_done = 1; - } - spin_unlock(&self->lock); - - return IRQ_HANDLED; -} - -static void bfin_sir_dma_rx_chars(struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - int i; - - UART_CLEAR_LSR(port); - - for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++) - async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]); -} - -static void bfin_sir_rx_dma_timeout(struct timer_list *t) -{ - struct bfin_sir_port *port = from_timer(port, t, rx_dma_timer); - struct net_device *dev = port->dev; - struct bfin_sir_self *self = netdev_priv(dev); - - int x_pos, pos; - unsigned long flags; - - spin_lock_irqsave(&self->lock, flags); - x_pos = DMA_SIR_RX_XCNT - get_dma_curr_xcount(port->rx_dma_channel); - if (x_pos == DMA_SIR_RX_XCNT) - x_pos = 0; - - pos = port->rx_dma_nrows * DMA_SIR_RX_XCNT + x_pos; - - if (pos > port->rx_dma_buf.tail) { - port->rx_dma_buf.tail = pos; - bfin_sir_dma_rx_chars(dev); - port->rx_dma_buf.head = port->rx_dma_buf.tail; - } - spin_unlock_irqrestore(&self->lock, flags); -} - -static irqreturn_t bfin_sir_dma_rx_int(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - unsigned short irqstat; - - spin_lock(&self->lock); - - port->rx_dma_nrows++; - port->rx_dma_buf.tail = DMA_SIR_RX_XCNT * port->rx_dma_nrows; - bfin_sir_dma_rx_chars(dev); - if (port->rx_dma_nrows >= DMA_SIR_RX_YCNT) { - port->rx_dma_nrows = 0; - port->rx_dma_buf.tail = 0; - } - port->rx_dma_buf.head = port->rx_dma_buf.tail; - - irqstat = get_dma_curr_irqstat(port->rx_dma_channel); - clear_dma_irqstat(port->rx_dma_channel); - spin_unlock(&self->lock); - - mod_timer(&port->rx_dma_timer, jiffies + DMA_SIR_RX_FLUSH_JIFS); - return IRQ_HANDLED; -} -#endif /* CONFIG_SIR_BFIN_DMA */ - -static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev) -{ -#ifdef CONFIG_SIR_BFIN_DMA - dma_addr_t dma_handle; -#endif /* CONFIG_SIR_BFIN_DMA */ - - if (request_dma(port->rx_dma_channel, "BFIN_UART_RX") < 0) { - dev_warn(&dev->dev, "Unable to attach SIR RX DMA channel\n"); - return -EBUSY; - } - - if (request_dma(port->tx_dma_channel, "BFIN_UART_TX") < 0) { - dev_warn(&dev->dev, "Unable to attach SIR TX DMA channel\n"); - free_dma(port->rx_dma_channel); - return -EBUSY; - } - -#ifdef CONFIG_SIR_BFIN_DMA - - set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev); - set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev); - - port->rx_dma_buf.buf = dma_alloc_coherent(NULL, PAGE_SIZE, - &dma_handle, GFP_DMA); - port->rx_dma_buf.head = 0; - port->rx_dma_buf.tail = 0; - port->rx_dma_nrows = 0; - - set_dma_config(port->rx_dma_channel, - set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, - INTR_ON_ROW, DIMENSION_2D, - DATA_SIZE_8, DMA_SYNC_RESTART)); - set_dma_x_count(port->rx_dma_channel, DMA_SIR_RX_XCNT); - set_dma_x_modify(port->rx_dma_channel, 1); - set_dma_y_count(port->rx_dma_channel, DMA_SIR_RX_YCNT); - set_dma_y_modify(port->rx_dma_channel, 1); - set_dma_start_addr(port->rx_dma_channel, (unsigned long)port->rx_dma_buf.buf); - enable_dma(port->rx_dma_channel); - - -#else - - if (request_irq(port->irq, bfin_sir_rx_int, 0, "BFIN_SIR_RX", dev)) { - dev_warn(&dev->dev, "Unable to attach SIR RX interrupt\n"); - return -EBUSY; - } - - if (request_irq(port->irq+1, bfin_sir_tx_int, 0, "BFIN_SIR_TX", dev)) { - dev_warn(&dev->dev, "Unable to attach SIR TX interrupt\n"); - free_irq(port->irq, dev); - return -EBUSY; - } -#endif - - return 0; -} - -static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev) -{ - unsigned short val; - - bfin_sir_stop_rx(port); - - val = UART_GET_GCTL(port); - val &= ~(UCEN | UMOD_MASK | RPOLC); - UART_PUT_GCTL(port, val); - -#ifdef CONFIG_SIR_BFIN_DMA - disable_dma(port->tx_dma_channel); - disable_dma(port->rx_dma_channel); - del_timer(&(port->rx_dma_timer)); - dma_free_coherent(NULL, PAGE_SIZE, port->rx_dma_buf.buf, 0); -#else - free_irq(port->irq+1, dev); - free_irq(port->irq, dev); -#endif - free_dma(port->tx_dma_channel); - free_dma(port->rx_dma_channel); -} - -#ifdef CONFIG_PM -static int bfin_sir_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct bfin_sir_port *sir_port; - struct net_device *dev; - struct bfin_sir_self *self; - - sir_port = platform_get_drvdata(pdev); - if (!sir_port) - return 0; - - dev = sir_port->dev; - self = netdev_priv(dev); - if (self->open) { - flush_work(&self->work); - bfin_sir_shutdown(self->sir_port, dev); - netif_device_detach(dev); - } - - return 0; -} -static int bfin_sir_resume(struct platform_device *pdev) -{ - struct bfin_sir_port *sir_port; - struct net_device *dev; - struct bfin_sir_self *self; - struct bfin_sir_port *port; - - sir_port = platform_get_drvdata(pdev); - if (!sir_port) - return 0; - - dev = sir_port->dev; - self = netdev_priv(dev); - port = self->sir_port; - if (self->open) { - if (self->newspeed) { - self->speed = self->newspeed; - self->newspeed = 0; - } - bfin_sir_startup(port, dev); - bfin_sir_set_speed(port, 9600); - bfin_sir_enable_rx(port); - netif_device_attach(dev); - } - return 0; -} -#else -#define bfin_sir_suspend NULL -#define bfin_sir_resume NULL -#endif - -static void bfin_sir_send_work(struct work_struct *work) -{ - struct bfin_sir_self *self = container_of(work, struct bfin_sir_self, work); - struct net_device *dev = self->sir_port->dev; - struct bfin_sir_port *port = self->sir_port; - unsigned short val; - int tx_cnt = 10; - - while (bfin_sir_is_receiving(dev) && --tx_cnt) - turnaround_delay(self->mtt); - - bfin_sir_stop_rx(port); - - /* To avoid losting RX interrupt, we reset IR function before - * sending data. We also can set the speed, which will - * reset all the UART. - */ - val = UART_GET_GCTL(port); - val &= ~(UMOD_MASK | RPOLC); - UART_PUT_GCTL(port, val); - SSYNC(); - val |= UMOD_IRDA | RPOLC; - UART_PUT_GCTL(port, val); - SSYNC(); - /* bfin_sir_set_speed(port, self->speed); */ - -#ifdef CONFIG_SIR_BFIN_DMA - bfin_sir_dma_tx_chars(dev); -#endif - bfin_sir_enable_tx(port); - netif_trans_update(dev); -} - -static int bfin_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - int speed = irda_get_next_speed(skb); - - netif_stop_queue(dev); - - self->mtt = irda_get_mtt(skb); - - if (speed != self->speed && speed != -1) - self->newspeed = speed; - - self->tx_buff.data = self->tx_buff.head; - if (skb->len == 0) - self->tx_buff.len = 0; - else - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); - - schedule_work(&self->work); - dev_kfree_skb(skb); - - return 0; -} - -static int bfin_sir_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) -{ - struct if_irda_req *rq = (struct if_irda_req *)ifreq; - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - int ret = 0; - - switch (cmd) { - case SIOCSBANDWIDTH: - if (capable(CAP_NET_ADMIN)) { - if (self->open) { - ret = bfin_sir_set_speed(port, rq->ifr_baudrate); - bfin_sir_enable_rx(port); - } else { - dev_warn(&dev->dev, "SIOCSBANDWIDTH: !netif_running\n"); - ret = 0; - } - } - break; - - case SIOCSMEDIABUSY: - ret = -EPERM; - if (capable(CAP_NET_ADMIN)) { - irda_device_set_media_busy(dev, TRUE); - ret = 0; - } - break; - - case SIOCGRECEIVING: - rq->ifr_receiving = bfin_sir_is_receiving(dev); - break; - - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - -static struct net_device_stats *bfin_sir_stats(struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - - return &self->stats; -} - -static int bfin_sir_open(struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - struct bfin_sir_port *port = self->sir_port; - int err; - - self->newspeed = 0; - self->speed = 9600; - - spin_lock_init(&self->lock); - - err = bfin_sir_startup(port, dev); - if (err) - goto err_startup; - - bfin_sir_set_speed(port, 9600); - - self->irlap = irlap_open(dev, &self->qos, DRIVER_NAME); - if (!self->irlap) { - err = -ENOMEM; - goto err_irlap; - } - - INIT_WORK(&self->work, bfin_sir_send_work); - - /* - * Now enable the interrupt then start the queue - */ - self->open = 1; - bfin_sir_enable_rx(port); - - netif_start_queue(dev); - - return 0; - -err_irlap: - self->open = 0; - bfin_sir_shutdown(port, dev); -err_startup: - return err; -} - -static int bfin_sir_stop(struct net_device *dev) -{ - struct bfin_sir_self *self = netdev_priv(dev); - - flush_work(&self->work); - bfin_sir_shutdown(self->sir_port, dev); - - if (self->rxskb) { - dev_kfree_skb(self->rxskb); - self->rxskb = NULL; - } - - /* Stop IrLAP */ - if (self->irlap) { - irlap_close(self->irlap); - self->irlap = NULL; - } - - netif_stop_queue(dev); - self->open = 0; - - return 0; -} - -static int bfin_sir_init_iobuf(iobuff_t *io, int size) -{ - io->head = kmalloc(size, GFP_KERNEL); - if (!io->head) - return -ENOMEM; - io->truesize = size; - io->in_frame = FALSE; - io->state = OUTSIDE_FRAME; - io->data = io->head; - return 0; -} - -static const struct net_device_ops bfin_sir_ndo = { - .ndo_open = bfin_sir_open, - .ndo_stop = bfin_sir_stop, - .ndo_start_xmit = bfin_sir_hard_xmit, - .ndo_do_ioctl = bfin_sir_ioctl, - .ndo_get_stats = bfin_sir_stats, -}; - -static int bfin_sir_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct bfin_sir_self *self; - unsigned int baudrate_mask; - struct bfin_sir_port *sir_port; - int err; - - if (pdev->id >= 0 && pdev->id < ARRAY_SIZE(per) && \ - per[pdev->id][3] == pdev->id) { - err = peripheral_request_list(per[pdev->id], DRIVER_NAME); - if (err) - return err; - } else { - dev_err(&pdev->dev, "Invalid pdev id, please check board file\n"); - return -ENODEV; - } - - err = -ENOMEM; - sir_port = kmalloc(sizeof(*sir_port), GFP_KERNEL); - if (!sir_port) - goto err_mem_0; - - bfin_sir_init_ports(sir_port, pdev); - - dev = alloc_irdadev(sizeof(*self)); - if (!dev) - goto err_mem_1; - - self = netdev_priv(dev); - self->dev = &pdev->dev; - self->sir_port = sir_port; - sir_port->dev = dev; - - err = bfin_sir_init_iobuf(&self->rx_buff, IRDA_SKB_MAX_MTU); - if (err) - goto err_mem_2; - err = bfin_sir_init_iobuf(&self->tx_buff, IRDA_SIR_MAX_FRAME); - if (err) - goto err_mem_3; - - dev->netdev_ops = &bfin_sir_ndo; - dev->irq = sir_port->irq; - - irda_init_max_qos_capabilies(&self->qos); - - baudrate_mask = IR_9600; - - switch (max_rate) { - case 115200: - baudrate_mask |= IR_115200; - case 57600: - baudrate_mask |= IR_57600; - case 38400: - baudrate_mask |= IR_38400; - case 19200: - baudrate_mask |= IR_19200; - case 9600: - break; - default: - dev_warn(&pdev->dev, "Invalid maximum baud rate, using 9600\n"); - } - - self->qos.baud_rate.bits &= baudrate_mask; - - self->qos.min_turn_time.bits = 1; /* 10 ms or more */ - - irda_qos_bits_to_value(&self->qos); - - err = register_netdev(dev); - - if (err) { - kfree(self->tx_buff.head); -err_mem_3: - kfree(self->rx_buff.head); -err_mem_2: - free_netdev(dev); -err_mem_1: - kfree(sir_port); -err_mem_0: - peripheral_free_list(per[pdev->id]); - } else - platform_set_drvdata(pdev, sir_port); - - return err; -} - -static int bfin_sir_remove(struct platform_device *pdev) -{ - struct bfin_sir_port *sir_port; - struct net_device *dev = NULL; - struct bfin_sir_self *self; - - sir_port = platform_get_drvdata(pdev); - if (!sir_port) - return 0; - dev = sir_port->dev; - self = netdev_priv(dev); - unregister_netdev(dev); - kfree(self->tx_buff.head); - kfree(self->rx_buff.head); - free_netdev(dev); - kfree(sir_port); - - return 0; -} - -static struct platform_driver bfin_ir_driver = { - .probe = bfin_sir_probe, - .remove = bfin_sir_remove, - .suspend = bfin_sir_suspend, - .resume = bfin_sir_resume, - .driver = { - .name = DRIVER_NAME, - }, -}; - -module_platform_driver(bfin_ir_driver); - -module_param(max_rate, int, 0); -MODULE_PARM_DESC(max_rate, "Maximum baud rate (115200, 57600, 38400, 19200, 9600)"); - -MODULE_AUTHOR("Graf Yang <graf.yang@analog.com>"); -MODULE_DESCRIPTION("Blackfin IrDA driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/bfin_sir.h b/drivers/staging/irda/drivers/bfin_sir.h deleted file mode 100644 index d47cf14bb4a5..000000000000 --- a/drivers/staging/irda/drivers/bfin_sir.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Blackfin Infra-red Driver - * - * Copyright 2006-2009 Analog Devices Inc. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - * - */ - -#include <linux/serial.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/irda_device.h> - -#include <asm/irq.h> -#include <asm/cacheflush.h> -#include <asm/dma.h> -#include <asm/portmux.h> -#undef DRIVER_NAME - -#ifdef CONFIG_SIR_BFIN_DMA -struct dma_rx_buf { - char *buf; - int head; - int tail; -}; -#endif - -struct bfin_sir_port { - unsigned char __iomem *membase; - unsigned int irq; - unsigned int lsr; - unsigned long clk; - struct net_device *dev; -#ifdef CONFIG_SIR_BFIN_DMA - int tx_done; - struct dma_rx_buf rx_dma_buf; - struct timer_list rx_dma_timer; - int rx_dma_nrows; -#endif - unsigned int tx_dma_channel; - unsigned int rx_dma_channel; -}; - -struct bfin_sir_port_res { - unsigned long base_addr; - int irq; - unsigned int rx_dma_channel; - unsigned int tx_dma_channel; -}; - -struct bfin_sir_self { - struct bfin_sir_port *sir_port; - spinlock_t lock; - unsigned int open; - int speed; - int newspeed; - - struct sk_buff *txskb; - struct sk_buff *rxskb; - struct net_device_stats stats; - struct device *dev; - struct irlap_cb *irlap; - struct qos_info qos; - - iobuff_t tx_buff; - iobuff_t rx_buff; - - struct work_struct work; - int mtt; -}; - -#define DRIVER_NAME "bfin_sir" - -#include <asm/bfin_serial.h> - -static const unsigned short per[][4] = { - /* rx pin tx pin NULL uart_number */ - {P_UART0_RX, P_UART0_TX, 0, 0}, - {P_UART1_RX, P_UART1_TX, 0, 1}, - {P_UART2_RX, P_UART2_TX, 0, 2}, - {P_UART3_RX, P_UART3_TX, 0, 3}, -}; diff --git a/drivers/staging/irda/drivers/donauboe.c b/drivers/staging/irda/drivers/donauboe.c deleted file mode 100644 index b337e6d23a88..000000000000 --- a/drivers/staging/irda/drivers/donauboe.c +++ /dev/null @@ -1,1732 +0,0 @@ -/***************************************************************** - * - * Filename: donauboe.c - * Version: 2.17 - * Description: Driver for the Toshiba OBOE (or type-O or 701) - * FIR Chipset, also supports the DONAUOBOE (type-DO - * or d01) FIR chipset which as far as I know is - * register compatible. - * Documentation: http://libxg.free.fr/irda/lib-irda.html - * Status: Experimental. - * Author: James McKenzie <james@fishsoup.dhs.org> - * Created at: Sat May 8 12:35:27 1999 - * Modified: Paul Bristow <paul.bristow@technologist.com> - * Modified: Mon Nov 11 19:10:05 1999 - * Modified: James McKenzie <james@fishsoup.dhs.org> - * Modified: Thu Mar 16 12:49:00 2000 (Substantial rewrite) - * Modified: Sat Apr 29 00:23:03 2000 (Added DONAUOBOE support) - * Modified: Wed May 24 23:45:02 2000 (Fixed chipio_t structure) - * Modified: 2.13 Christian Gennerat <christian.gennerat@polytechnique.org> - * Modified: 2.13 dim jan 07 21:57:39 2001 (tested with kernel 2.4 & irnet/ppp) - * Modified: 2.14 Christian Gennerat <christian.gennerat@polytechnique.org> - * Modified: 2.14 lun fev 05 17:55:59 2001 (adapted to patch-2.4.1-pre8-irda1) - * Modified: 2.15 Martin Lucina <mato@kotelna.sk> - * Modified: 2.15 Fri Jun 21 20:40:59 2002 (sync with 2.4.18, substantial fixes) - * Modified: 2.16 Martin Lucina <mato@kotelna.sk> - * Modified: 2.16 Sat Jun 22 18:54:29 2002 (fix freeregion, default to verbose) - * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org> - * Modified: 2.17 jeu sep 12 08:50:20 2002 (save_flags();cli(); replaced by spinlocks) - * Modified: 2.18 Christian Gennerat <christian.gennerat@polytechnique.org> - * Modified: 2.18 ven jan 10 03:14:16 2003 Change probe default options - * - * Copyright (c) 1999 James McKenzie, All Rights Reserved. - * - * 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. - * - * Neither James McKenzie nor Cambridge University admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - * Applicable Models : Libretto 100/110CT and many more. - * Toshiba refers to this chip as the type-O IR port, - * or the type-DO IR port. - * - ********************************************************************/ - -/* Look at toshoboe.h (currently in include/net/irda) for details of */ -/* Where to get documentation on the chip */ - -/* See below for a description of the logic in this driver */ - -/* User servicable parts */ -/* USE_PROBE Create the code which probes the chip and does a few tests */ -/* do_probe module parameter Enable this code */ -/* Probe code is very useful for understanding how the hardware works */ -/* Use it with various combinations of TT_LEN, RX_LEN */ -/* Strongly recommended, disable if the probe fails on your machine */ -/* and send me <james@fishsoup.dhs.org> the output of dmesg */ -#define USE_PROBE 1 -#undef USE_PROBE - -/* Trace Transmit ring, interrupts, Receive ring or not ? */ -#define PROBE_VERBOSE 1 - -/* Debug option, examine sent and received raw data */ -/* Irdadump is better, but does not see all packets. enable it if you want. */ -#undef DUMP_PACKETS - -/* MIR mode has not been tested. Some behaviour is different */ -/* Seems to work against an Ericsson R520 for me. -Martin */ -#define USE_MIR - -/* Schedule back to back hardware transmits wherever possible, otherwise */ -/* we need an interrupt for every frame, unset if oboe works for a bit and */ -/* then hangs */ -#define OPTIMIZE_TX - -/* Set the number of slots in the rings */ -/* If you get rx/tx fifo overflows at high bitrates, you can try increasing */ -/* these */ - -#define RING_SIZE (OBOE_RING_SIZE_RX8 | OBOE_RING_SIZE_TX8) -#define TX_SLOTS 8 -#define RX_SLOTS 8 - - -/* Less user servicable parts below here */ - -/* Test, Transmit and receive buffer sizes, adjust at your peril */ -/* remarks: nfs usually needs 1k blocks */ -/* remarks: in SIR mode, CRC is received, -> RX_LEN=TX_LEN+2 */ -/* remarks: test accepts large blocks. Standard is 0x80 */ -/* When TT_LEN > RX_LEN (SIR mode) data is stored in successive slots. */ -/* When 3 or more slots are needed for each test packet, */ -/* data received in the first slots is overwritten, even */ -/* if OBOE_CTL_RX_HW_OWNS is not set, without any error! */ -#define TT_LEN 0x80 -#define TX_LEN 0xc00 -#define RX_LEN 0xc04 -/* Real transmitted length (SIR mode) is about 14+(2%*TX_LEN) more */ -/* long than user-defined length (see async_wrap_skb) and is less then 4K */ -/* Real received length is (max RX_LEN) differs from user-defined */ -/* length only b the CRC (2 or 4 bytes) */ -#define BUF_SAFETY 0x7a -#define RX_BUF_SZ (RX_LEN) -#define TX_BUF_SZ (TX_LEN+BUF_SAFETY) - - -/* Logic of the netdev part of this driver */ - -/* The RX ring is filled with buffers, when a packet arrives */ -/* it is DMA'd into the buffer which is marked used and RxDone called */ -/* RxDone forms an skb (and checks the CRC if in SIR mode) and ships */ -/* the packet off upstairs */ - -/* The transmitter on the oboe chip can work in one of two modes */ -/* for each ring->tx[] the transmitter can either */ -/* a) transmit the packet, leave the trasmitter enabled and proceed to */ -/* the next ring */ -/* OR */ -/* b) transmit the packet, switch off the transmitter and issue TxDone */ - -/* All packets are entered into the ring in mode b), if the ring was */ -/* empty the transmitter is started. */ - -/* If OPTIMIZE_TX is defined then in TxDone if the ring contains */ -/* more than one packet, all but the last are set to mode a) [HOWEVER */ -/* the hardware may not notice this, this is why we start in mode b) ] */ -/* then restart the transmitter */ - -/* If OPTIMIZE_TX is not defined then we just restart the transmitter */ -/* if the ring isn't empty */ - -/* Speed changes are delayed until the TxRing is empty */ -/* mtt is handled by generating packets with bad CRCs, before the data */ - -/* TODO: */ -/* check the mtt works ok */ -/* finish the watchdog */ - -/* No user servicable parts below here */ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/rtnetlink.h> - -#include <asm/io.h> - -#include <net/irda/wrapper.h> -#include <net/irda/irda.h> -//#include <net/irda/irmod.h> -//#include <net/irda/irlap_frame.h> -#include <net/irda/irda_device.h> -#include <net/irda/crc.h> - -#include "donauboe.h" - -#define INB(port) inb_p(port) -#define OUTB(val,port) outb_p(val,port) -#define OUTBP(val,port) outb_p(val,port) - -#define PROMPT OUTB(OBOE_PROMPT_BIT,OBOE_PROMPT); - -#if PROBE_VERBOSE -#define PROBE_DEBUG(args...) (printk (args)) -#else -#define PROBE_DEBUG(args...) ; -#endif - -/* Set the DMA to be byte at a time */ -#define CONFIG0H_DMA_OFF OBOE_CONFIG0H_RCVANY -#define CONFIG0H_DMA_ON_NORX CONFIG0H_DMA_OFF| OBOE_CONFIG0H_ENDMAC -#define CONFIG0H_DMA_ON CONFIG0H_DMA_ON_NORX | OBOE_CONFIG0H_ENRX - -static const struct pci_device_id toshoboe_pci_tbl[] = { - { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIRD01, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl); - -#define DRIVER_NAME "toshoboe" -static char *driver_name = DRIVER_NAME; - -static int max_baud = 4000000; -#ifdef USE_PROBE -static bool do_probe = false; -#endif - - -/**********************************************************************/ -static int -toshoboe_checkfcs (unsigned char *buf, int len) -{ - int i; - union - { - __u16 value; - __u8 bytes[2]; - } - fcs; - - fcs.value = INIT_FCS; - - for (i = 0; i < len; ++i) - fcs.value = irda_fcs (fcs.value, *(buf++)); - - return fcs.value == GOOD_FCS; -} - -/***********************************************************************/ -/* Generic chip handling code */ -#ifdef DUMP_PACKETS -static unsigned char dump[50]; -static void -_dumpbufs (unsigned char *data, int len, char tete) -{ -int i,j; -char head=tete; -for (i=0;i<len;i+=16) { - for (j=0;j<16 && i+j<len;j++) { sprintf(&dump[3*j],"%02x.",data[i+j]); } - dump [3*j]=0; - pr_debug("%c%s\n", head, dump); - head='+'; - } -} -#endif - -#ifdef USE_PROBE -/* Dump the registers */ -static void -toshoboe_dumpregs (struct toshoboe_cb *self) -{ - __u32 ringbase; - - ringbase = INB (OBOE_RING_BASE0) << 10; - ringbase |= INB (OBOE_RING_BASE1) << 18; - ringbase |= INB (OBOE_RING_BASE2) << 26; - - printk (KERN_ERR DRIVER_NAME ": Register dump:\n"); - printk (KERN_ERR "Interrupts: Tx:%d Rx:%d TxUnder:%d RxOver:%d Sip:%d\n", - self->int_tx, self->int_rx, self->int_txunder, self->int_rxover, - self->int_sip); - printk (KERN_ERR "RX %02x TX %02x RingBase %08x\n", - INB (OBOE_RXSLOT), INB (OBOE_TXSLOT), ringbase); - printk (KERN_ERR "RING_SIZE %02x IER %02x ISR %02x\n", - INB (OBOE_RING_SIZE), INB (OBOE_IER), INB (OBOE_ISR)); - printk (KERN_ERR "CONFIG1 %02x STATUS %02x\n", - INB (OBOE_CONFIG1), INB (OBOE_STATUS)); - printk (KERN_ERR "CONFIG0 %02x%02x ENABLE %02x%02x\n", - INB (OBOE_CONFIG0H), INB (OBOE_CONFIG0L), - INB (OBOE_ENABLEH), INB (OBOE_ENABLEL)); - printk (KERN_ERR "NEW_PCONFIG %02x%02x CURR_PCONFIG %02x%02x\n", - INB (OBOE_NEW_PCONFIGH), INB (OBOE_NEW_PCONFIGL), - INB (OBOE_CURR_PCONFIGH), INB (OBOE_CURR_PCONFIGL)); - printk (KERN_ERR "MAXLEN %02x%02x RXCOUNT %02x%02x\n", - INB (OBOE_MAXLENH), INB (OBOE_MAXLENL), - INB (OBOE_RXCOUNTL), INB (OBOE_RXCOUNTH)); - - if (self->ring) - { - int i; - ringbase = virt_to_bus (self->ring); - printk (KERN_ERR "Ring at %08x:\n", ringbase); - printk (KERN_ERR "RX:"); - for (i = 0; i < RX_SLOTS; ++i) - printk (" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control); - printk ("\n"); - printk (KERN_ERR "TX:"); - for (i = 0; i < RX_SLOTS; ++i) - printk (" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control); - printk ("\n"); - } -} -#endif - -/*Don't let the chip look at memory */ -static void -toshoboe_disablebm (struct toshoboe_cb *self) -{ - __u8 command; - pci_read_config_byte (self->pdev, PCI_COMMAND, &command); - command &= ~PCI_COMMAND_MASTER; - pci_write_config_byte (self->pdev, PCI_COMMAND, command); - -} - -/* Shutdown the chip and point the taskfile reg somewhere else */ -static void -toshoboe_stopchip (struct toshoboe_cb *self) -{ - /*Disable interrupts */ - OUTB (0x0, OBOE_IER); - /*Disable DMA, Disable Rx, Disable Tx */ - OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); - /*Disable SIR MIR FIR, Tx and Rx */ - OUTB (0x00, OBOE_ENABLEH); - /*Point the ring somewhere safe */ - OUTB (0x3f, OBOE_RING_BASE2); - OUTB (0xff, OBOE_RING_BASE1); - OUTB (0xff, OBOE_RING_BASE0); - - OUTB (RX_LEN >> 8, OBOE_MAXLENH); - OUTB (RX_LEN & 0xff, OBOE_MAXLENL); - - /*Acknoledge any pending interrupts */ - OUTB (0xff, OBOE_ISR); - - /*Why */ - OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); - - /*switch it off */ - OUTB (OBOE_CONFIG1_OFF, OBOE_CONFIG1); - - toshoboe_disablebm (self); -} - -/* Transmitter initialization */ -static void -toshoboe_start_DMA (struct toshoboe_cb *self, int opts) -{ - OUTB (0x0, OBOE_ENABLEH); - OUTB (CONFIG0H_DMA_ON | opts, OBOE_CONFIG0H); - OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); - PROMPT; -} - -/*Set the baud rate */ -static void -toshoboe_setbaud (struct toshoboe_cb *self) -{ - __u16 pconfig = 0; - __u8 config0l = 0; - - pr_debug("%s(%d/%d)\n", __func__, self->speed, self->io.speed); - - switch (self->speed) - { - case 2400: - case 4800: - case 9600: - case 19200: - case 38400: - case 57600: - case 115200: -#ifdef USE_MIR - case 1152000: -#endif - case 4000000: - break; - default: - - printk (KERN_ERR DRIVER_NAME ": switch to unsupported baudrate %d\n", - self->speed); - return; - } - - switch (self->speed) - { - /* For SIR the preamble is done by adding XBOFs */ - /* to the packet */ - /* set to filtered SIR mode, filter looks for BOF and EOF */ - case 2400: - pconfig |= 47 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; - break; - case 4800: - pconfig |= 23 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; - break; - case 9600: - pconfig |= 11 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; - break; - case 19200: - pconfig |= 5 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; - break; - case 38400: - pconfig |= 2 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; - break; - case 57600: - pconfig |= 1 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; - break; - case 115200: - pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 25 << OBOE_PCONFIG_WIDTHSHIFT; - break; - default: - /*Set to packet based reception */ - OUTB (RX_LEN >> 8, OBOE_MAXLENH); - OUTB (RX_LEN & 0xff, OBOE_MAXLENL); - break; - } - - switch (self->speed) - { - case 2400: - case 4800: - case 9600: - case 19200: - case 38400: - case 57600: - case 115200: - config0l = OBOE_CONFIG0L_ENSIR; - if (self->async) - { - /*Set to character based reception */ - /*System will lock if MAXLEN=0 */ - /*so have to be careful */ - OUTB (0x01, OBOE_MAXLENH); - OUTB (0x01, OBOE_MAXLENL); - OUTB (0x00, OBOE_MAXLENH); - } - else - { - /*Set to packet based reception */ - config0l |= OBOE_CONFIG0L_ENSIRF; - OUTB (RX_LEN >> 8, OBOE_MAXLENH); - OUTB (RX_LEN & 0xff, OBOE_MAXLENL); - } - break; - -#ifdef USE_MIR - /* MIR mode */ - /* Set for 16 bit CRC and enable MIR */ - /* Preamble now handled by the chip */ - case 1152000: - pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; - pconfig |= 8 << OBOE_PCONFIG_WIDTHSHIFT; - pconfig |= 1 << OBOE_PCONFIG_PREAMBLESHIFT; - config0l = OBOE_CONFIG0L_CRC16 | OBOE_CONFIG0L_ENMIR; - break; -#endif - /* FIR mode */ - /* Set for 32 bit CRC and enable FIR */ - /* Preamble handled by the chip */ - case 4000000: - pconfig |= 0 << OBOE_PCONFIG_BAUDSHIFT; - /* Documentation says 14, but toshiba use 15 in their drivers */ - pconfig |= 15 << OBOE_PCONFIG_PREAMBLESHIFT; - config0l = OBOE_CONFIG0L_ENFIR; - break; - } - - /* Copy into new PHY config buffer */ - OUTBP (pconfig >> 8, OBOE_NEW_PCONFIGH); - OUTB (pconfig & 0xff, OBOE_NEW_PCONFIGL); - OUTB (config0l, OBOE_CONFIG0L); - - /* Now make OBOE copy from new PHY to current PHY */ - OUTB (0x0, OBOE_ENABLEH); - OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); - PROMPT; - - /* speed change executed */ - self->new_speed = 0; - self->io.speed = self->speed; -} - -/*Let the chip look at memory */ -static void -toshoboe_enablebm (struct toshoboe_cb *self) -{ - pci_set_master (self->pdev); -} - -/*setup the ring */ -static void -toshoboe_initring (struct toshoboe_cb *self) -{ - int i; - - for (i = 0; i < TX_SLOTS; ++i) - { - self->ring->tx[i].len = 0; - self->ring->tx[i].control = 0x00; - self->ring->tx[i].address = virt_to_bus (self->tx_bufs[i]); - } - - for (i = 0; i < RX_SLOTS; ++i) - { - self->ring->rx[i].len = RX_LEN; - self->ring->rx[i].len = 0; - self->ring->rx[i].address = virt_to_bus (self->rx_bufs[i]); - self->ring->rx[i].control = OBOE_CTL_RX_HW_OWNS; - } -} - -static void -toshoboe_resetptrs (struct toshoboe_cb *self) -{ - /* Can reset pointers by twidling DMA */ - OUTB (0x0, OBOE_ENABLEH); - OUTBP (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); - OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); - - self->rxs = inb_p (OBOE_RXSLOT) & OBOE_SLOT_MASK; - self->txs = inb_p (OBOE_TXSLOT) & OBOE_SLOT_MASK; -} - -/* Called in locked state */ -static void -toshoboe_initptrs (struct toshoboe_cb *self) -{ - - /* spin_lock_irqsave(self->spinlock, flags); */ - /* save_flags (flags); */ - - /* Can reset pointers by twidling DMA */ - toshoboe_resetptrs (self); - - OUTB (0x0, OBOE_ENABLEH); - OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H); - OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); - - self->txpending = 0; - - /* spin_unlock_irqrestore(self->spinlock, flags); */ - /* restore_flags (flags); */ -} - -/* Wake the chip up and get it looking at the rings */ -/* Called in locked state */ -static void -toshoboe_startchip (struct toshoboe_cb *self) -{ - __u32 physaddr; - - toshoboe_initring (self); - toshoboe_enablebm (self); - OUTBP (OBOE_CONFIG1_RESET, OBOE_CONFIG1); - OUTBP (OBOE_CONFIG1_ON, OBOE_CONFIG1); - - /* Stop the clocks */ - OUTB (0, OBOE_ENABLEH); - - /*Set size of rings */ - OUTB (RING_SIZE, OBOE_RING_SIZE); - - /*Acknoledge any pending interrupts */ - OUTB (0xff, OBOE_ISR); - - /*Enable ints */ - OUTB (OBOE_INT_TXDONE | OBOE_INT_RXDONE | - OBOE_INT_TXUNDER | OBOE_INT_RXOVER | OBOE_INT_SIP , OBOE_IER); - - /*Acknoledge any pending interrupts */ - OUTB (0xff, OBOE_ISR); - - /*Set the maximum packet length to 0xfff (4095) */ - OUTB (RX_LEN >> 8, OBOE_MAXLENH); - OUTB (RX_LEN & 0xff, OBOE_MAXLENL); - - /*Shutdown DMA */ - OUTB (CONFIG0H_DMA_OFF, OBOE_CONFIG0H); - - /*Find out where the rings live */ - physaddr = virt_to_bus (self->ring); - - IRDA_ASSERT ((physaddr & 0x3ff) == 0, - printk (KERN_ERR DRIVER_NAME "ring not correctly aligned\n"); - return;); - - OUTB ((physaddr >> 10) & 0xff, OBOE_RING_BASE0); - OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1); - OUTB ((physaddr >> 26) & 0x3f, OBOE_RING_BASE2); - - /*Enable DMA controller in byte mode and RX */ - OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H); - - /* Start up the clocks */ - OUTB (OBOE_ENABLEH_PHYANDCLOCK, OBOE_ENABLEH); - - /*set to sensible speed */ - self->speed = 9600; - toshoboe_setbaud (self); - toshoboe_initptrs (self); -} - -static void -toshoboe_isntstuck (struct toshoboe_cb *self) -{ -} - -static void -toshoboe_checkstuck (struct toshoboe_cb *self) -{ - unsigned long flags; - - if (0) - { - spin_lock_irqsave(&self->spinlock, flags); - - /* This will reset the chip completely */ - printk (KERN_ERR DRIVER_NAME ": Resetting chip\n"); - - toshoboe_stopchip (self); - toshoboe_startchip (self); - spin_unlock_irqrestore(&self->spinlock, flags); - } -} - -/*Generate packet of about mtt us long */ -static int -toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt) -{ - int xbofs; - - xbofs = ((int) (mtt/100)) * (int) (self->speed); - xbofs=xbofs/80000; /*Eight bits per byte, and mtt is in us*/ - xbofs++; - - pr_debug(DRIVER_NAME ": generated mtt of %d bytes for %d us at %d baud\n", - xbofs, mtt, self->speed); - - if (xbofs > TX_LEN) - { - printk (KERN_ERR DRIVER_NAME ": wanted %d bytes MTT but TX_LEN is %d\n", - xbofs, TX_LEN); - xbofs = TX_LEN; - } - - /*xbofs will do for SIR, MIR and FIR,SIR mode doesn't generate a checksum anyway */ - memset (buf, XBOF, xbofs); - - return xbofs; -} - -#ifdef USE_PROBE -/***********************************************************************/ -/* Probe code */ - -static void -toshoboe_dumptx (struct toshoboe_cb *self) -{ - int i; - PROBE_DEBUG(KERN_WARNING "TX:"); - for (i = 0; i < RX_SLOTS; ++i) - PROBE_DEBUG(" (%d,%02x)",self->ring->tx[i].len,self->ring->tx[i].control); - PROBE_DEBUG(" [%d]\n",self->speed); -} - -static void -toshoboe_dumprx (struct toshoboe_cb *self, int score) -{ - int i; - PROBE_DEBUG(" %d\nRX:",score); - for (i = 0; i < RX_SLOTS; ++i) - PROBE_DEBUG(" (%d,%02x)",self->ring->rx[i].len,self->ring->rx[i].control); - PROBE_DEBUG("\n"); -} - -static inline int -stuff_byte (__u8 byte, __u8 * buf) -{ - switch (byte) - { - case BOF: /* FALLTHROUGH */ - case EOF: /* FALLTHROUGH */ - case CE: - /* Insert transparently coded */ - buf[0] = CE; /* Send link escape */ - buf[1] = byte ^ IRDA_TRANS; /* Complement bit 5 */ - return 2; - /* break; */ - default: - /* Non-special value, no transparency required */ - buf[0] = byte; - return 1; - /* break; */ - } -} - -static irqreturn_t -toshoboe_probeinterrupt (int irq, void *dev_id) -{ - struct toshoboe_cb *self = dev_id; - __u8 irqstat; - - irqstat = INB (OBOE_ISR); - -/* was it us */ - if (!(irqstat & OBOE_INT_MASK)) - return IRQ_NONE; - -/* Ack all the interrupts */ - OUTB (irqstat, OBOE_ISR); - - if (irqstat & OBOE_INT_TXDONE) - { - int txp; - - self->int_tx++; - PROBE_DEBUG("T"); - - txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK; - if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS) - { - self->int_tx+=100; - PROBE_DEBUG("S"); - toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); - } - } - - if (irqstat & OBOE_INT_RXDONE) { - self->int_rx++; - PROBE_DEBUG("R"); } - if (irqstat & OBOE_INT_TXUNDER) { - self->int_txunder++; - PROBE_DEBUG("U"); } - if (irqstat & OBOE_INT_RXOVER) { - self->int_rxover++; - PROBE_DEBUG("O"); } - if (irqstat & OBOE_INT_SIP) { - self->int_sip++; - PROBE_DEBUG("I"); } - return IRQ_HANDLED; -} - -static int -toshoboe_maketestpacket (unsigned char *buf, int badcrc, int fir) -{ - int i; - int len = 0; - union - { - __u16 value; - __u8 bytes[2]; - } - fcs; - - if (fir) - { - memset (buf, 0, TT_LEN); - return TT_LEN; - } - - fcs.value = INIT_FCS; - - memset (buf, XBOF, 10); - len += 10; - buf[len++] = BOF; - - for (i = 0; i < TT_LEN; ++i) - { - len += stuff_byte (i, buf + len); - fcs.value = irda_fcs (fcs.value, i); - } - - len += stuff_byte (fcs.bytes[0] ^ badcrc, buf + len); - len += stuff_byte (fcs.bytes[1] ^ badcrc, buf + len); - buf[len++] = EOF; - len++; - return len; -} - -static int -toshoboe_probefail (struct toshoboe_cb *self, char *msg) -{ - printk (KERN_ERR DRIVER_NAME "probe(%d) failed %s\n",self-> speed, msg); - toshoboe_dumpregs (self); - toshoboe_stopchip (self); - free_irq (self->io.irq, (void *) self); - return 0; -} - -static int -toshoboe_numvalidrcvs (struct toshoboe_cb *self) -{ - int i, ret = 0; - for (i = 0; i < RX_SLOTS; ++i) - if ((self->ring->rx[i].control & 0xe0) == 0) - ret++; - - return ret; -} - -static int -toshoboe_numrcvs (struct toshoboe_cb *self) -{ - int i, ret = 0; - for (i = 0; i < RX_SLOTS; ++i) - if (!(self->ring->rx[i].control & OBOE_CTL_RX_HW_OWNS)) - ret++; - - return ret; -} - -static int -toshoboe_probe (struct toshoboe_cb *self) -{ - int i, j, n; -#ifdef USE_MIR - static const int bauds[] = { 9600, 115200, 4000000, 1152000 }; -#else - static const int bauds[] = { 9600, 115200, 4000000 }; -#endif - unsigned long flags; - - if (request_irq (self->io.irq, toshoboe_probeinterrupt, - self->io.irqflags, "toshoboe", (void *) self)) - { - printk (KERN_ERR DRIVER_NAME ": probe failed to allocate irq %d\n", - self->io.irq); - return 0; - } - - /* test 1: SIR filter and back to back */ - - for (j = 0; j < ARRAY_SIZE(bauds); ++j) - { - int fir = (j > 1); - toshoboe_stopchip (self); - - - spin_lock_irqsave(&self->spinlock, flags); - /*Address is already setup */ - toshoboe_startchip (self); - self->int_rx = self->int_tx = 0; - self->speed = bauds[j]; - toshoboe_setbaud (self); - toshoboe_initptrs (self); - spin_unlock_irqrestore(&self->spinlock, flags); - - self->ring->tx[self->txs].control = -/* (FIR only) OBOE_CTL_TX_SIP needed for switching to next slot */ -/* MIR: all received data is stored in one slot */ - (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX - : OBOE_CTL_TX_HW_OWNS ; - self->ring->tx[self->txs].len = - toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); - self->txs++; - self->txs %= TX_SLOTS; - - self->ring->tx[self->txs].control = - (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_SIP - : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ; - self->ring->tx[self->txs].len = - toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); - self->txs++; - self->txs %= TX_SLOTS; - - self->ring->tx[self->txs].control = - (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX - : OBOE_CTL_TX_HW_OWNS ; - self->ring->tx[self->txs].len = - toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); - self->txs++; - self->txs %= TX_SLOTS; - - self->ring->tx[self->txs].control = - (fir) ? OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX - | OBOE_CTL_TX_SIP | OBOE_CTL_TX_BAD_CRC - : OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX ; - self->ring->tx[self->txs].len = - toshoboe_maketestpacket (self->tx_bufs[self->txs], 0, fir); - self->txs++; - self->txs %= TX_SLOTS; - - toshoboe_dumptx (self); - /* Turn on TX and RX and loopback */ - toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); - - i = 0; - n = fir ? 1 : 4; - while (toshoboe_numvalidrcvs (self) != n) - { - if (i > 4800) - return toshoboe_probefail (self, "filter test"); - udelay ((9600*(TT_LEN+16))/self->speed); - i++; - } - - n = fir ? 203 : 102; - while ((toshoboe_numrcvs(self) != self->int_rx) || (self->int_tx != n)) - { - if (i > 4800) - return toshoboe_probefail (self, "interrupt test"); - udelay ((9600*(TT_LEN+16))/self->speed); - i++; - } - toshoboe_dumprx (self,i); - - } - - /* test 2: SIR in char at a time */ - - toshoboe_stopchip (self); - self->int_rx = self->int_tx = 0; - - spin_lock_irqsave(&self->spinlock, flags); - toshoboe_startchip (self); - spin_unlock_irqrestore(&self->spinlock, flags); - - self->async = 1; - self->speed = 115200; - toshoboe_setbaud (self); - self->ring->tx[self->txs].control = - OBOE_CTL_TX_RTCENTX | OBOE_CTL_TX_HW_OWNS; - self->ring->tx[self->txs].len = 4; - - ((unsigned char *) self->tx_bufs[self->txs])[0] = 'f'; - ((unsigned char *) self->tx_bufs[self->txs])[1] = 'i'; - ((unsigned char *) self->tx_bufs[self->txs])[2] = 's'; - ((unsigned char *) self->tx_bufs[self->txs])[3] = 'h'; - toshoboe_dumptx (self); - toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); - - i = 0; - while (toshoboe_numvalidrcvs (self) != 4) - { - if (i > 100) - return toshoboe_probefail (self, "Async test"); - udelay (100); - i++; - } - - while ((toshoboe_numrcvs (self) != self->int_rx) || (self->int_tx != 1)) - { - if (i > 100) - return toshoboe_probefail (self, "Async interrupt test"); - udelay (100); - i++; - } - toshoboe_dumprx (self,i); - - self->async = 0; - self->speed = 9600; - toshoboe_setbaud (self); - toshoboe_stopchip (self); - - free_irq (self->io.irq, (void *) self); - - printk (KERN_WARNING DRIVER_NAME ": Self test passed ok\n"); - - return 1; -} -#endif - -/******************************************************************/ -/* Netdev style code */ - -/* Transmit something */ -static netdev_tx_t -toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) -{ - struct toshoboe_cb *self; - __s32 speed; - int mtt, len, ctl; - unsigned long flags; - struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; - - self = netdev_priv(dev); - - IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; ); - - pr_debug("%s.tx:%x(%x)%x\n", - __func__, skb->len, self->txpending, INB(OBOE_ENABLEH)); - if (!cb->magic) { - pr_debug("%s.Not IrLAP:%x\n", __func__, cb->magic); -#ifdef DUMP_PACKETS - _dumpbufs(skb->data,skb->len,'>'); -#endif - } - - /* change speed pending, wait for its execution */ - if (self->new_speed) - return NETDEV_TX_BUSY; - - /* device stopped (apm) wait for restart */ - if (self->stopped) - return NETDEV_TX_BUSY; - - toshoboe_checkstuck (self); - - /* Check if we need to change the speed */ - /* But not now. Wait after transmission if mtt not required */ - speed=irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) - { - spin_lock_irqsave(&self->spinlock, flags); - - if (self->txpending || skb->len) - { - self->new_speed = speed; - pr_debug("%s: Queued TxDone scheduled speed change %d\n" , - __func__, speed); - /* if no data, that's all! */ - if (!skb->len) - { - spin_unlock_irqrestore(&self->spinlock, flags); - dev_kfree_skb (skb); - return NETDEV_TX_OK; - } - /* True packet, go on, but */ - /* do not accept anything before change speed execution */ - netif_stop_queue(dev); - /* ready to process TxDone interrupt */ - spin_unlock_irqrestore(&self->spinlock, flags); - } - else - { - /* idle and no data, change speed now */ - self->speed = speed; - toshoboe_setbaud (self); - spin_unlock_irqrestore(&self->spinlock, flags); - dev_kfree_skb (skb); - return NETDEV_TX_OK; - } - - } - - if ((mtt = irda_get_mtt(skb))) - { - /* This is fair since the queue should be empty anyway */ - spin_lock_irqsave(&self->spinlock, flags); - - if (self->txpending) - { - spin_unlock_irqrestore(&self->spinlock, flags); - return NETDEV_TX_BUSY; - } - - /* If in SIR mode we need to generate a string of XBOFs */ - /* In MIR and FIR we need to generate a string of data */ - /* which we will add a wrong checksum to */ - - mtt = toshoboe_makemttpacket (self, self->tx_bufs[self->txs], mtt); - pr_debug("%s.mtt:%x(%x)%d\n", __func__, skb->len, mtt, self->txpending); - if (mtt) - { - self->ring->tx[self->txs].len = mtt & 0xfff; - - ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX; - if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON) - { - ctl |= OBOE_CTL_TX_BAD_CRC | OBOE_CTL_TX_SIP ; - } -#ifdef USE_MIR - else if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_MIRON) - { - ctl |= OBOE_CTL_TX_BAD_CRC; - } -#endif - self->ring->tx[self->txs].control = ctl; - - OUTB (0x0, OBOE_ENABLEH); - /* It is only a timer. Do not send mtt packet outside! */ - toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX | OBOE_CONFIG0H_LOOP); - - self->txpending++; - - self->txs++; - self->txs %= TX_SLOTS; - - } - else - { - printk(KERN_ERR DRIVER_NAME ": problem with mtt packet - ignored\n"); - } - spin_unlock_irqrestore(&self->spinlock, flags); - } - -#ifdef DUMP_PACKETS -dumpbufs(skb->data,skb->len,'>'); -#endif - - spin_lock_irqsave(&self->spinlock, flags); - - if (self->ring->tx[self->txs].control & OBOE_CTL_TX_HW_OWNS) - { - pr_debug("%s.ful:%x(%x)%x\n", - __func__, skb->len, self->ring->tx[self->txs].control, - self->txpending); - toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); - spin_unlock_irqrestore(&self->spinlock, flags); - return NETDEV_TX_BUSY; - } - - if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_SIRON) - { - len = async_wrap_skb (skb, self->tx_bufs[self->txs], TX_BUF_SZ); - } - else - { - len = skb->len; - skb_copy_from_linear_data(skb, self->tx_bufs[self->txs], len); - } - self->ring->tx[self->txs].len = len & 0x0fff; - - /*Sometimes the HW doesn't see us assert RTCENTX in the interrupt code */ - /*later this plays safe, we garuntee the last packet to be transmitted */ - /*has RTCENTX set */ - - ctl = OBOE_CTL_TX_HW_OWNS | OBOE_CTL_TX_RTCENTX; - if (INB (OBOE_ENABLEH) & OBOE_ENABLEH_FIRON) - { - ctl |= OBOE_CTL_TX_SIP ; - } - self->ring->tx[self->txs].control = ctl; - - /* If transmitter is idle start in one-shot mode */ - - if (!self->txpending) - toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); - - self->txpending++; - - self->txs++; - self->txs %= TX_SLOTS; - - spin_unlock_irqrestore(&self->spinlock, flags); - dev_kfree_skb (skb); - - return NETDEV_TX_OK; -} - -/*interrupt handler */ -static irqreturn_t -toshoboe_interrupt (int irq, void *dev_id) -{ - struct toshoboe_cb *self = dev_id; - __u8 irqstat; - struct sk_buff *skb = NULL; - - irqstat = INB (OBOE_ISR); - -/* was it us */ - if (!(irqstat & OBOE_INT_MASK)) - return IRQ_NONE; - -/* Ack all the interrupts */ - OUTB (irqstat, OBOE_ISR); - - toshoboe_isntstuck (self); - -/* Txdone */ - if (irqstat & OBOE_INT_TXDONE) - { - int txp, txpc; - int i; - - txp = self->txpending; - self->txpending = 0; - - for (i = 0; i < TX_SLOTS; ++i) - { - if (self->ring->tx[i].control & OBOE_CTL_TX_HW_OWNS) - self->txpending++; - } - pr_debug("%s.txd(%x)%x/%x\n", __func__, irqstat, txp, self->txpending); - - txp = INB (OBOE_TXSLOT) & OBOE_SLOT_MASK; - - /* Got anything queued ? start it together */ - if (self->ring->tx[txp].control & OBOE_CTL_TX_HW_OWNS) - { - txpc = txp; -#ifdef OPTIMIZE_TX - while (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS) - { - txp = txpc; - txpc++; - txpc %= TX_SLOTS; - self->netdev->stats.tx_packets++; - if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS) - self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX; - } - self->netdev->stats.tx_packets--; -#else - self->netdev->stats.tx_packets++; -#endif - toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); - } - - if ((!self->txpending) && (self->new_speed)) - { - self->speed = self->new_speed; - pr_debug("%s: Executed TxDone scheduled speed change %d\n", - __func__, self->speed); - toshoboe_setbaud (self); - } - - /* Tell network layer that we want more frames */ - if (!self->new_speed) - netif_wake_queue(self->netdev); - } - - if (irqstat & OBOE_INT_RXDONE) - { - while (!(self->ring->rx[self->rxs].control & OBOE_CTL_RX_HW_OWNS)) - { - int len = self->ring->rx[self->rxs].len; - skb = NULL; - pr_debug("%s.rcv:%x(%x)\n", __func__ - , len, self->ring->rx[self->rxs].control); - -#ifdef DUMP_PACKETS -dumpbufs(self->rx_bufs[self->rxs],len,'<'); -#endif - - if (self->ring->rx[self->rxs].control == 0) - { - __u8 enable = INB (OBOE_ENABLEH); - - /* In SIR mode we need to check the CRC as this */ - /* hasn't been done by the hardware */ - if (enable & OBOE_ENABLEH_SIRON) - { - if (!toshoboe_checkfcs (self->rx_bufs[self->rxs], len)) - len = 0; - /*Trim off the CRC */ - if (len > 1) - len -= 2; - else - len = 0; - pr_debug("%s.SIR:%x(%x)\n", __func__, len, enable); - } - -#ifdef USE_MIR - else if (enable & OBOE_ENABLEH_MIRON) - { - if (len > 1) - len -= 2; - else - len = 0; - pr_debug("%s.MIR:%x(%x)\n", __func__, len, enable); - } -#endif - else if (enable & OBOE_ENABLEH_FIRON) - { - if (len > 3) - len -= 4; /*FIXME: check this */ - else - len = 0; - pr_debug("%s.FIR:%x(%x)\n", __func__, len, enable); - } - else - pr_debug("%s.?IR:%x(%x)\n", __func__, len, enable); - - if (len) - { - skb = dev_alloc_skb (len + 1); - if (skb) - { - skb_reserve (skb, 1); - - skb_put (skb, len); - skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs], - len); - self->netdev->stats.rx_packets++; - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons (ETH_P_IRDA); - } - else - { - printk (KERN_INFO - "%s(), memory squeeze, dropping frame.\n", - __func__); - } - } - } - else - { - /* TODO: =========================================== */ - /* if OBOE_CTL_RX_LENGTH, our buffers are too small */ - /* (MIR or FIR) data is lost. */ - /* (SIR) data is splitted in several slots. */ - /* we have to join all the received buffers received */ - /*in a large buffer before checking CRC. */ - pr_debug("%s.err:%x(%x)\n", __func__ - , len, self->ring->rx[self->rxs].control); - } - - self->ring->rx[self->rxs].len = 0x0; - self->ring->rx[self->rxs].control = OBOE_CTL_RX_HW_OWNS; - - self->rxs++; - self->rxs %= RX_SLOTS; - - if (skb) - netif_rx (skb); - - } - } - - if (irqstat & OBOE_INT_TXUNDER) - { - printk (KERN_WARNING DRIVER_NAME ": tx fifo underflow\n"); - } - if (irqstat & OBOE_INT_RXOVER) - { - printk (KERN_WARNING DRIVER_NAME ": rx fifo overflow\n"); - } -/* This must be useful for something... */ - if (irqstat & OBOE_INT_SIP) - { - self->int_sip++; - pr_debug("%s.sip:%x(%x)%x\n", - __func__, self->int_sip, irqstat, self->txpending); - } - return IRQ_HANDLED; -} - - -static int -toshoboe_net_open (struct net_device *dev) -{ - struct toshoboe_cb *self; - unsigned long flags; - int rc; - - self = netdev_priv(dev); - - if (self->async) - return -EBUSY; - - if (self->stopped) - return 0; - - rc = request_irq (self->io.irq, toshoboe_interrupt, - IRQF_SHARED, dev->name, self); - if (rc) - return rc; - - spin_lock_irqsave(&self->spinlock, flags); - toshoboe_startchip (self); - spin_unlock_irqrestore(&self->spinlock, flags); - - /* Ready to play! */ - netif_start_queue(dev); - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open (dev, &self->qos, driver_name); - - self->irdad = 1; - - return 0; -} - -static int -toshoboe_net_close (struct net_device *dev) -{ - struct toshoboe_cb *self; - - IRDA_ASSERT (dev != NULL, return -1; ); - self = netdev_priv(dev); - - /* Stop device */ - netif_stop_queue(dev); - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close (self->irlap); - self->irlap = NULL; - - self->irdad = 0; - - free_irq (self->io.irq, (void *) self); - - if (!self->stopped) - { - toshoboe_stopchip (self); - } - - return 0; -} - -/* - * Function toshoboe_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int -toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct toshoboe_cb *self; - unsigned long flags; - int ret = 0; - - IRDA_ASSERT (dev != NULL, return -1; ); - - self = netdev_priv(dev); - - IRDA_ASSERT (self != NULL, return -1; ); - - pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); - - /* Disable interrupts & save flags */ - spin_lock_irqsave(&self->spinlock, flags); - - switch (cmd) - { - case SIOCSBANDWIDTH: /* Set bandwidth */ - /* This function will also be used by IrLAP to change the - * speed, so we still must allow for speed change within - * interrupt context. - */ - pr_debug("%s(BANDWIDTH), %s, (%X/%ld\n", - __func__, dev->name, INB(OBOE_STATUS), irq->ifr_baudrate); - if (!in_interrupt () && !capable (CAP_NET_ADMIN)) { - ret = -EPERM; - goto out; - } - - /* self->speed=irq->ifr_baudrate; */ - /* toshoboe_setbaud(self); */ - /* Just change speed once - inserted by Paul Bristow */ - self->new_speed = irq->ifr_baudrate; - break; - case SIOCSMEDIABUSY: /* Set media busy */ - pr_debug("%s(MEDIABUSY), %s, (%X/%x)\n", - __func__, dev->name, - INB(OBOE_STATUS), capable(CAP_NET_ADMIN)); - if (!capable (CAP_NET_ADMIN)) { - ret = -EPERM; - goto out; - } - irda_device_set_media_busy (self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = (INB (OBOE_STATUS) & OBOE_STATUS_RXBUSY) ? 1 : 0; - pr_debug("%s(RECEIVING), %s, (%X/%x)\n", - __func__, dev->name, INB(OBOE_STATUS), irq->ifr_receiving); - break; - default: - pr_debug("%s(?), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); - ret = -EOPNOTSUPP; - } -out: - spin_unlock_irqrestore(&self->spinlock, flags); - return ret; - -} - -MODULE_DESCRIPTION("Toshiba OBOE IrDA Device Driver"); -MODULE_AUTHOR("James McKenzie <james@fishsoup.dhs.org>"); -MODULE_LICENSE("GPL"); - -module_param (max_baud, int, 0); -MODULE_PARM_DESC(max_baud, "Maximum baud rate"); - -#ifdef USE_PROBE -module_param (do_probe, bool, 0); -MODULE_PARM_DESC(do_probe, "Enable/disable chip probing and self-test"); -#endif - -static void -toshoboe_close (struct pci_dev *pci_dev) -{ - int i; - struct toshoboe_cb *self = pci_get_drvdata(pci_dev); - - IRDA_ASSERT (self != NULL, return; ); - - if (!self->stopped) - { - toshoboe_stopchip (self); - } - - release_region (self->io.fir_base, self->io.fir_ext); - - for (i = 0; i < TX_SLOTS; ++i) - { - kfree (self->tx_bufs[i]); - self->tx_bufs[i] = NULL; - } - - for (i = 0; i < RX_SLOTS; ++i) - { - kfree (self->rx_bufs[i]); - self->rx_bufs[i] = NULL; - } - - unregister_netdev(self->netdev); - - kfree (self->ringbuf); - self->ringbuf = NULL; - self->ring = NULL; - - free_netdev(self->netdev); -} - -static const struct net_device_ops toshoboe_netdev_ops = { - .ndo_open = toshoboe_net_open, - .ndo_stop = toshoboe_net_close, - .ndo_start_xmit = toshoboe_hard_xmit, - .ndo_do_ioctl = toshoboe_net_ioctl, -}; - -static int -toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) -{ - struct toshoboe_cb *self; - struct net_device *dev; - int i = 0; - int ok = 0; - int err; - - if ((err=pci_enable_device(pci_dev))) - return err; - - dev = alloc_irdadev(sizeof (struct toshoboe_cb)); - if (dev == NULL) - { - printk (KERN_ERR DRIVER_NAME ": can't allocate memory for " - "IrDA control block\n"); - return -ENOMEM; - } - - self = netdev_priv(dev); - self->netdev = dev; - self->pdev = pci_dev; - self->base = pci_resource_start(pci_dev,0); - - self->io.fir_base = self->base; - self->io.fir_ext = OBOE_IO_EXTENT; - self->io.irq = pci_dev->irq; - self->io.irqflags = IRQF_SHARED; - - self->speed = self->io.speed = 9600; - self->async = 0; - - /* Lock the port that we need */ - if (NULL==request_region (self->io.fir_base, self->io.fir_ext, driver_name)) - { - printk (KERN_ERR DRIVER_NAME ": can't get iobase of 0x%03x\n" - ,self->io.fir_base); - err = -EBUSY; - goto freeself; - } - - spin_lock_init(&self->spinlock); - - irda_init_max_qos_capabilies (&self->qos); - self->qos.baud_rate.bits = 0; - - if (max_baud >= 2400) - self->qos.baud_rate.bits |= IR_2400; - /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */ - if (max_baud >= 9600) - self->qos.baud_rate.bits |= IR_9600; - if (max_baud >= 19200) - self->qos.baud_rate.bits |= IR_19200; - if (max_baud >= 115200) - self->qos.baud_rate.bits |= IR_115200; -#ifdef USE_MIR - if (max_baud >= 1152000) - { - self->qos.baud_rate.bits |= IR_1152000; - } -#endif - if (max_baud >= 4000000) - { - self->qos.baud_rate.bits |= (IR_4000000 << 8); - } - - /*FIXME: work this out... */ - self->qos.min_turn_time.bits = 0xff; - - irda_qos_bits_to_value (&self->qos); - - /* Allocate twice the size to guarantee alignment */ - self->ringbuf = kmalloc(OBOE_RING_LEN << 1, GFP_KERNEL); - if (!self->ringbuf) - { - err = -ENOMEM; - goto freeregion; - } - -#if (BITS_PER_LONG == 64) -#error broken on 64-bit: casts pointer to 32-bit, and then back to pointer. -#endif - - /*We need to align the taskfile on a taskfile size boundary */ - { - unsigned long addr; - - addr = (__u32) self->ringbuf; - addr &= ~(OBOE_RING_LEN - 1); - addr += OBOE_RING_LEN; - self->ring = (struct OboeRing *) addr; - } - - memset (self->ring, 0, OBOE_RING_LEN); - self->io.mem_base = (__u32) self->ring; - - ok = 1; - for (i = 0; i < TX_SLOTS; ++i) - { - self->tx_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL); - if (!self->tx_bufs[i]) - ok = 0; - } - - for (i = 0; i < RX_SLOTS; ++i) - { - self->rx_bufs[i] = kmalloc (RX_BUF_SZ, GFP_KERNEL); - if (!self->rx_bufs[i]) - ok = 0; - } - - if (!ok) - { - err = -ENOMEM; - goto freebufs; - } - - -#ifdef USE_PROBE - if (do_probe) - if (!toshoboe_probe (self)) - { - err = -ENODEV; - goto freebufs; - } -#endif - - SET_NETDEV_DEV(dev, &pci_dev->dev); - dev->netdev_ops = &toshoboe_netdev_ops; - - err = register_netdev(dev); - if (err) - { - printk (KERN_ERR DRIVER_NAME ": register_netdev() failed\n"); - err = -ENOMEM; - goto freebufs; - } - printk (KERN_INFO "IrDA: Registered device %s\n", dev->name); - - pci_set_drvdata(pci_dev,self); - - printk (KERN_INFO DRIVER_NAME ": Using multiple tasks\n"); - - return 0; - -freebufs: - for (i = 0; i < TX_SLOTS; ++i) - kfree (self->tx_bufs[i]); - for (i = 0; i < RX_SLOTS; ++i) - kfree (self->rx_bufs[i]); - kfree(self->ringbuf); - -freeregion: - release_region (self->io.fir_base, self->io.fir_ext); - -freeself: - free_netdev(dev); - - return err; -} - -static int -toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap) -{ - struct toshoboe_cb *self = pci_get_drvdata(pci_dev); - unsigned long flags; - int i = 10; - - if (!self || self->stopped) - return 0; - - if ((!self->irdad) && (!self->async)) - return 0; - -/* Flush all packets */ - while ((i--) && (self->txpending)) - msleep(10); - - spin_lock_irqsave(&self->spinlock, flags); - - toshoboe_stopchip (self); - self->stopped = 1; - self->txpending = 0; - - spin_unlock_irqrestore(&self->spinlock, flags); - return 0; -} - -static int -toshoboe_wakeup (struct pci_dev *pci_dev) -{ - struct toshoboe_cb *self = pci_get_drvdata(pci_dev); - unsigned long flags; - - if (!self || !self->stopped) - return 0; - - if ((!self->irdad) && (!self->async)) - return 0; - - spin_lock_irqsave(&self->spinlock, flags); - - toshoboe_startchip (self); - self->stopped = 0; - - netif_wake_queue(self->netdev); - spin_unlock_irqrestore(&self->spinlock, flags); - return 0; -} - -static struct pci_driver donauboe_pci_driver = { - .name = "donauboe", - .id_table = toshoboe_pci_tbl, - .probe = toshoboe_open, - .remove = toshoboe_close, - .suspend = toshoboe_gotosleep, - .resume = toshoboe_wakeup -}; - -module_pci_driver(donauboe_pci_driver); diff --git a/drivers/staging/irda/drivers/donauboe.h b/drivers/staging/irda/drivers/donauboe.h deleted file mode 100644 index d92d54e839b9..000000000000 --- a/drivers/staging/irda/drivers/donauboe.h +++ /dev/null @@ -1,362 +0,0 @@ -/********************************************************************* - * - * Filename: toshoboe.h - * Version: 2.16 - * Description: Driver for the Toshiba OBOE (or type-O or 701) - * FIR Chipset, also supports the DONAUOBOE (type-DO - * or d01) FIR chipset which as far as I know is - * register compatible. - * Status: Experimental. - * Author: James McKenzie <james@fishsoup.dhs.org> - * Created at: Sat May 8 12:35:27 1999 - * Modified: 2.16 Martin Lucina <mato@kotelna.sk> - * Modified: 2.16 Sat Jun 22 18:54:29 2002 (sync headers) - * Modified: 2.17 Christian Gennerat <christian.gennerat@polytechnique.org> - * Modified: 2.17 jeu sep 12 08:50:20 2002 (add lock to be used by spinlocks) - * - * Copyright (c) 1999 James McKenzie, All Rights Reserved. - * - * 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. - * - * Neither James McKenzie nor Cambridge University admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - * Applicable Models : Libretto 100/110CT and many more. - * Toshiba refers to this chip as the type-O IR port, - * or the type-DO IR port. - * - * IrDA chip set list from Toshiba Computer Engineering Corp. - * model method maker controller Version - * Portege 320CT FIR,SIR Toshiba Oboe(Triangle) - * Portege 3010CT FIR,SIR Toshiba Oboe(Sydney) - * Portege 3015CT FIR,SIR Toshiba Oboe(Sydney) - * Portege 3020CT FIR,SIR Toshiba Oboe(Sydney) - * Portege 7020CT FIR,SIR ? ? - * - * Satell. 4090XCDT FIR,SIR ? ? - * - * Libretto 100CT FIR,SIR Toshiba Oboe - * Libretto 1000CT FIR,SIR Toshiba Oboe - * - * TECRA750DVD FIR,SIR Toshiba Oboe(Triangle) REV ID=14h - * TECRA780 FIR,SIR Toshiba Oboe(Sandlot) REV ID=32h,33h - * TECRA750CDT FIR,SIR Toshiba Oboe(Triangle) REV ID=13h,14h - * TECRA8000 FIR,SIR Toshiba Oboe(ISKUR) REV ID=23h - * - ********************************************************************/ - -/* The documentation for this chip is allegedly released */ -/* However I have not seen it, not have I managed to contact */ -/* anyone who has. HOWEVER the chip bears a striking resemblance */ -/* to the IrDA controller in the Toshiba RISC TMPR3922 chip */ -/* the documentation for this is freely available at */ -/* http://www.madingley.org/james/resources/toshoboe/TMPR3922.pdf */ -/* The mapping between the registers in that document and the */ -/* Registers in the 701 oboe chip are as follows */ - - -/* 3922 reg 701 regs, by bit numbers */ -/* 7- 0 15- 8 24-16 31-25 */ -/* $28 0x0 0x1 */ -/* $2c SEE NOTE 1 */ -/* $30 0x6 0x7 */ -/* $34 0x8 0x9 SEE NOTE 2 */ -/* $38 0x10 0x11 */ -/* $3C 0xe SEE NOTE 3 */ -/* $40 0x12 0x13 */ -/* $44 0x14 0x15 */ -/* $48 0x16 0x17 */ -/* $4c 0x18 0x19 */ -/* $50 0x1a 0x1b */ - -/* FIXME: could be 0x1b 0x1a here */ - -/* $54 0x1d 0x1c */ -/* $5C 0xf SEE NOTE 4 */ -/* $130 SEE NOTE 5 */ -/* $134 SEE NOTE 6 */ -/* */ -/* NOTES: */ -/* 1. The pointer to ring is packed in most unceremoniusly */ -/* 701 Register Address bits (A9-A0 must be zero) */ -/* 0x4: A17 A16 A15 A14 A13 A12 A11 A10 */ -/* 0x5: A25 A24 A23 A22 A21 A20 A19 A18 */ -/* 0x2: 0 0 A31 A30 A29 A28 A27 A26 */ -/* */ -/* 2. The M$ drivers do a write 0x1 to 0x9, however the 3922 */ -/* documentation would suggest that a write of 0x1 to 0x8 */ -/* would be more appropriate. */ -/* */ -/* 3. This assignment is tenuous at best, register 0xe seems to */ -/* have bits arranged 0 0 0 R/W R/W R/W R/W R/W */ -/* if either of the lower two bits are set the chip seems to */ -/* switch off */ -/* */ -/* 4. Bits 7-4 seem to be different 4 seems just to be generic */ -/* receiver busy flag */ -/* */ -/* 5. and 6. The IER and ISR have a different bit assignment */ -/* The lower three bits of both read back as ones */ -/* ISR is register 0xc, IER is register 0xd */ -/* 7 6 5 4 3 2 1 0 */ -/* 0xc: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */ -/* 0xd: TxDone RxDone TxUndr RxOver SipRcv 1 1 1 */ -/* TxDone xmitt done (generated only if generate interrupt bit */ -/* is set in the ring) */ -/* RxDone recv completed (or other recv condition if you set it */ -/* up */ -/* TxUnder underflow in Transmit FIFO */ -/* RxOver overflow in Recv FIFO */ -/* SipRcv received serial gap (or other condition you set) */ -/* Interrupts are enabled by writing a one to the IER register */ -/* Interrupts are cleared by writing a one to the ISR register */ -/* */ -/* 6. The remaining registers: 0x6 and 0x3 appear to be */ -/* reserved parts of 16 or 32 bit registersthe remainder */ -/* 0xa 0xb 0x1e 0x1f could possibly be (by their behaviour) */ -/* the Unicast Filter register at $58. */ -/* */ -/* 7. While the core obviously expects 32 bit accesses all the */ -/* M$ drivers do 8 bit accesses, infact the Miniport ones */ -/* write and read back the byte serveral times (why?) */ - - -#ifndef TOSHOBOE_H -#define TOSHOBOE_H - -/* Registers */ - -#define OBOE_IO_EXTENT 0x1f - -/*Receive and transmit slot pointers */ -#define OBOE_REG(i) (i+(self->base)) -#define OBOE_RXSLOT OBOE_REG(0x0) -#define OBOE_TXSLOT OBOE_REG(0x1) -#define OBOE_SLOT_MASK 0x3f - -#define OBOE_TXRING_OFFSET 0x200 -#define OBOE_TXRING_OFFSET_IN_SLOTS 0x40 - -/*pointer to the ring */ -#define OBOE_RING_BASE0 OBOE_REG(0x4) -#define OBOE_RING_BASE1 OBOE_REG(0x5) -#define OBOE_RING_BASE2 OBOE_REG(0x2) -#define OBOE_RING_BASE3 OBOE_REG(0x3) - -/*Number of slots in the ring */ -#define OBOE_RING_SIZE OBOE_REG(0x7) -#define OBOE_RING_SIZE_RX4 0x00 -#define OBOE_RING_SIZE_RX8 0x01 -#define OBOE_RING_SIZE_RX16 0x03 -#define OBOE_RING_SIZE_RX32 0x07 -#define OBOE_RING_SIZE_RX64 0x0f -#define OBOE_RING_SIZE_TX4 0x00 -#define OBOE_RING_SIZE_TX8 0x10 -#define OBOE_RING_SIZE_TX16 0x30 -#define OBOE_RING_SIZE_TX32 0x70 -#define OBOE_RING_SIZE_TX64 0xf0 - -#define OBOE_RING_MAX_SIZE 64 - -/*Causes the gubbins to re-examine the ring */ -#define OBOE_PROMPT OBOE_REG(0x9) -#define OBOE_PROMPT_BIT 0x1 - -/* Interrupt Status Register */ -#define OBOE_ISR OBOE_REG(0xc) -/* Interrupt Enable Register */ -#define OBOE_IER OBOE_REG(0xd) -/* Interrupt bits for IER and ISR */ -#define OBOE_INT_TXDONE 0x80 -#define OBOE_INT_RXDONE 0x40 -#define OBOE_INT_TXUNDER 0x20 -#define OBOE_INT_RXOVER 0x10 -#define OBOE_INT_SIP 0x08 -#define OBOE_INT_MASK 0xf8 - -/*Reset Register */ -#define OBOE_CONFIG1 OBOE_REG(0xe) -#define OBOE_CONFIG1_RST 0x01 -#define OBOE_CONFIG1_DISABLE 0x02 -#define OBOE_CONFIG1_4 0x08 -#define OBOE_CONFIG1_8 0x08 - -#define OBOE_CONFIG1_ON 0x8 -#define OBOE_CONFIG1_RESET 0xf -#define OBOE_CONFIG1_OFF 0xe - -#define OBOE_STATUS OBOE_REG(0xf) -#define OBOE_STATUS_RXBUSY 0x10 -#define OBOE_STATUS_FIRRX 0x04 -#define OBOE_STATUS_MIRRX 0x02 -#define OBOE_STATUS_SIRRX 0x01 - - -/*Speed control registers */ -#define OBOE_CONFIG0L OBOE_REG(0x10) -#define OBOE_CONFIG0H OBOE_REG(0x11) - -#define OBOE_CONFIG0H_TXONLOOP 0x80 /*Transmit when looping (dangerous) */ -#define OBOE_CONFIG0H_LOOP 0x40 /*Loopback Tx->Rx */ -#define OBOE_CONFIG0H_ENTX 0x10 /*Enable Tx */ -#define OBOE_CONFIG0H_ENRX 0x08 /*Enable Rx */ -#define OBOE_CONFIG0H_ENDMAC 0x04 /*Enable/reset* the DMA controller */ -#define OBOE_CONFIG0H_RCVANY 0x02 /*DMA mode 1=bytes, 0=dwords */ - -#define OBOE_CONFIG0L_CRC16 0x80 /*CRC 1=16 bit 0=32 bit */ -#define OBOE_CONFIG0L_ENFIR 0x40 /*Enable FIR */ -#define OBOE_CONFIG0L_ENMIR 0x20 /*Enable MIR */ -#define OBOE_CONFIG0L_ENSIR 0x10 /*Enable SIR */ -#define OBOE_CONFIG0L_ENSIRF 0x08 /*Enable SIR framer */ -#define OBOE_CONFIG0L_SIRTEST 0x04 /*Enable SIR framer in MIR and FIR */ -#define OBOE_CONFIG0L_INVERTTX 0x02 /*Invert Tx Line */ -#define OBOE_CONFIG0L_INVERTRX 0x01 /*Invert Rx Line */ - -#define OBOE_BOF OBOE_REG(0x12) -#define OBOE_EOF OBOE_REG(0x13) - -#define OBOE_ENABLEL OBOE_REG(0x14) -#define OBOE_ENABLEH OBOE_REG(0x15) - -#define OBOE_ENABLEH_PHYANDCLOCK 0x80 /*Toggle low to copy config in */ -#define OBOE_ENABLEH_CONFIGERR 0x40 -#define OBOE_ENABLEH_FIRON 0x20 -#define OBOE_ENABLEH_MIRON 0x10 -#define OBOE_ENABLEH_SIRON 0x08 -#define OBOE_ENABLEH_ENTX 0x04 -#define OBOE_ENABLEH_ENRX 0x02 -#define OBOE_ENABLEH_CRC16 0x01 - -#define OBOE_ENABLEL_BROADCAST 0x01 - -#define OBOE_CURR_PCONFIGL OBOE_REG(0x16) /*Current config */ -#define OBOE_CURR_PCONFIGH OBOE_REG(0x17) - -#define OBOE_NEW_PCONFIGL OBOE_REG(0x18) -#define OBOE_NEW_PCONFIGH OBOE_REG(0x19) - -#define OBOE_PCONFIGH_BAUDMASK 0xfc -#define OBOE_PCONFIGH_WIDTHMASK 0x04 -#define OBOE_PCONFIGL_WIDTHMASK 0xe0 -#define OBOE_PCONFIGL_PREAMBLEMASK 0x1f - -#define OBOE_PCONFIG_BAUDMASK 0xfc00 -#define OBOE_PCONFIG_BAUDSHIFT 10 -#define OBOE_PCONFIG_WIDTHMASK 0x04e0 -#define OBOE_PCONFIG_WIDTHSHIFT 5 -#define OBOE_PCONFIG_PREAMBLEMASK 0x001f -#define OBOE_PCONFIG_PREAMBLESHIFT 0 - -#define OBOE_MAXLENL OBOE_REG(0x1a) -#define OBOE_MAXLENH OBOE_REG(0x1b) - -#define OBOE_RXCOUNTH OBOE_REG(0x1c) /*Reset on recipt */ -#define OBOE_RXCOUNTL OBOE_REG(0x1d) /*of whole packet */ - -/* The PCI ID of the OBOE chip */ -#ifndef PCI_DEVICE_ID_FIR701 -#define PCI_DEVICE_ID_FIR701 0x0701 -#endif - -#ifndef PCI_DEVICE_ID_FIRD01 -#define PCI_DEVICE_ID_FIRD01 0x0d01 -#endif - -struct OboeSlot -{ - __u16 len; /*Tweleve bits of packet length */ - __u8 unused; - __u8 control; /*Slot control/status see below */ - __u32 address; /*Slot buffer address */ -} -__packed; - -#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS - -struct OboeRing -{ - struct OboeSlot rx[OBOE_NTASKS]; - struct OboeSlot tx[OBOE_NTASKS]; -}; - -#define OBOE_RING_LEN (sizeof(struct OboeRing)) - - -#define OBOE_CTL_TX_HW_OWNS 0x80 /*W/R This slot owned by the hardware */ -#define OBOE_CTL_TX_DISTX_CRC 0x40 /*W Disable CRC generation for [FM]IR */ -#define OBOE_CTL_TX_BAD_CRC 0x20 /*W Generate bad CRC */ -#define OBOE_CTL_TX_SIP 0x10 /*W Generate an SIP after xmittion */ -#define OBOE_CTL_TX_MKUNDER 0x08 /*W Generate an underrun error */ -#define OBOE_CTL_TX_RTCENTX 0x04 /*W Enable receiver and generate TXdone */ - /* After this slot is processed */ -#define OBOE_CTL_TX_UNDER 0x01 /*R Set by hardware to indicate underrun */ - - -#define OBOE_CTL_RX_HW_OWNS 0x80 /*W/R This slot owned by hardware */ -#define OBOE_CTL_RX_PHYERR 0x40 /*R Decoder error on receiption */ -#define OBOE_CTL_RX_CRCERR 0x20 /*R CRC error only set for [FM]IR */ -#define OBOE_CTL_RX_LENGTH 0x10 /*R Packet > max Rx length */ -#define OBOE_CTL_RX_OVER 0x08 /*R set to indicate an overflow */ -#define OBOE_CTL_RX_SIRBAD 0x04 /*R SIR had BOF in packet or ABORT sequence */ -#define OBOE_CTL_RX_RXEOF 0x02 /*R Finished receiving on this slot */ - - -struct toshoboe_cb -{ - struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct tty_driver ttydev; - - struct irlap_cb *irlap; /* The link layer we are binded to */ - - chipio_t io; /* IrDA controller information */ - struct qos_info qos; /* QoS capabilities for this device */ - - __u32 flags; /* Interface flags */ - - struct pci_dev *pdev; /*PCI device */ - int base; /*IO base */ - - - int txpending; /*how many tx's are pending */ - int txs, rxs; /*Which slots are we at */ - - int irdad; /*Driver under control of netdev end */ - int async; /*Driver under control of async end */ - - - int stopped; /*Stopped by some or other APM stuff */ - - int filter; /*In SIR mode do we want to receive - frames or byte ranges */ - - void *ringbuf; /*The ring buffer */ - struct OboeRing *ring; /*The ring */ - - void *tx_bufs[OBOE_RING_MAX_SIZE]; /*The buffers */ - void *rx_bufs[OBOE_RING_MAX_SIZE]; - - - int speed; /*Current setting of the speed */ - int new_speed; /*Set to request a speed change */ - -/* The spinlock protect critical parts of the driver. - * Locking is done like this : - * spin_lock_irqsave(&self->spinlock, flags); - * Releasing the lock : - * spin_unlock_irqrestore(&self->spinlock, flags); - */ - spinlock_t spinlock; - /* Used for the probe and diagnostics code */ - int int_rx; - int int_tx; - int int_txunder; - int int_rxover; - int int_sip; -}; - - -#endif diff --git a/drivers/staging/irda/drivers/esi-sir.c b/drivers/staging/irda/drivers/esi-sir.c deleted file mode 100644 index eb7aa6430bea..000000000000 --- a/drivers/staging/irda/drivers/esi-sir.c +++ /dev/null @@ -1,157 +0,0 @@ -/********************************************************************* - * - * Filename: esi.c - * Version: 1.6 - * Description: Driver for the Extended Systems JetEye PC dongle - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Sun Oct 27 22:01:04 2002 - * Modified by: Martin Diehl <mad@mdiehl.de> - * - * Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>, - * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>, - * Copyright (c) 2002 Martin Diehl, <mad@mdiehl.de>, - * All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -static int esi_open(struct sir_dev *); -static int esi_close(struct sir_dev *); -static int esi_change_speed(struct sir_dev *, unsigned); -static int esi_reset(struct sir_dev *); - -static struct dongle_driver esi = { - .owner = THIS_MODULE, - .driver_name = "JetEye PC ESI-9680 PC", - .type = IRDA_ESI_DONGLE, - .open = esi_open, - .close = esi_close, - .reset = esi_reset, - .set_speed = esi_change_speed, -}; - -static int __init esi_sir_init(void) -{ - return irda_register_dongle(&esi); -} - -static void __exit esi_sir_cleanup(void) -{ - irda_unregister_dongle(&esi); -} - -static int esi_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - /* Power up and set dongle to 9600 baud */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - - qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200; - qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int esi_close(struct sir_dev *dev) -{ - /* Power off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function esi_change_speed (task) - * - * Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle - * Apparently (see old esi-driver) no delays are needed here... - * - */ -static int esi_change_speed(struct sir_dev *dev, unsigned speed) -{ - int ret = 0; - int dtr, rts; - - switch (speed) { - case 19200: - dtr = TRUE; - rts = FALSE; - break; - case 115200: - dtr = rts = TRUE; - break; - default: - ret = -EINVAL; - speed = 9600; - /* fall through */ - case 9600: - dtr = FALSE; - rts = TRUE; - break; - } - - /* Change speed of dongle */ - sirdev_set_dtr_rts(dev, dtr, rts); - dev->speed = speed; - - return ret; -} - -/* - * Function esi_reset (task) - * - * Reset dongle; - * - */ -static int esi_reset(struct sir_dev *dev) -{ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - /* Hm, the old esi-driver left the dongle unpowered relying on - * the following speed change to repower. This might work for - * the esi because we only need the modem lines. However, now the - * general rule is reset must bring the dongle to some working - * well-known state because speed change might write to registers. - * The old esi-driver didn't any delay here - let's hope it' fine. - */ - - sirdev_set_dtr_rts(dev, FALSE, TRUE); - dev->speed = 9600; - - return 0; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-1"); /* IRDA_ESI_DONGLE */ - -module_init(esi_sir_init); -module_exit(esi_sir_cleanup); - diff --git a/drivers/staging/irda/drivers/girbil-sir.c b/drivers/staging/irda/drivers/girbil-sir.c deleted file mode 100644 index 7e0a5b8c6d53..000000000000 --- a/drivers/staging/irda/drivers/girbil-sir.c +++ /dev/null @@ -1,252 +0,0 @@ -/********************************************************************* - * - * Filename: girbil.c - * Version: 1.2 - * Description: Implementation for the Greenwich GIrBIL dongle - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Feb 6 21:02:33 1999 - * Modified at: Fri Dec 17 09:13:20 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -static int girbil_reset(struct sir_dev *dev); -static int girbil_open(struct sir_dev *dev); -static int girbil_close(struct sir_dev *dev); -static int girbil_change_speed(struct sir_dev *dev, unsigned speed); - -/* Control register 1 */ -#define GIRBIL_TXEN 0x01 /* Enable transmitter */ -#define GIRBIL_RXEN 0x02 /* Enable receiver */ -#define GIRBIL_ECAN 0x04 /* Cancel self emitted data */ -#define GIRBIL_ECHO 0x08 /* Echo control characters */ - -/* LED Current Register (0x2) */ -#define GIRBIL_HIGH 0x20 -#define GIRBIL_MEDIUM 0x21 -#define GIRBIL_LOW 0x22 - -/* Baud register (0x3) */ -#define GIRBIL_2400 0x30 -#define GIRBIL_4800 0x31 -#define GIRBIL_9600 0x32 -#define GIRBIL_19200 0x33 -#define GIRBIL_38400 0x34 -#define GIRBIL_57600 0x35 -#define GIRBIL_115200 0x36 - -/* Mode register (0x4) */ -#define GIRBIL_IRDA 0x40 -#define GIRBIL_ASK 0x41 - -/* Control register 2 (0x5) */ -#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */ - -static struct dongle_driver girbil = { - .owner = THIS_MODULE, - .driver_name = "Greenwich GIrBIL", - .type = IRDA_GIRBIL_DONGLE, - .open = girbil_open, - .close = girbil_close, - .reset = girbil_reset, - .set_speed = girbil_change_speed, -}; - -static int __init girbil_sir_init(void) -{ - return irda_register_dongle(&girbil); -} - -static void __exit girbil_sir_cleanup(void) -{ - irda_unregister_dongle(&girbil); -} - -static int girbil_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - /* Power on dongle */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x03; - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int girbil_close(struct sir_dev *dev) -{ - /* Power off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function girbil_change_speed (dev, speed) - * - * Set the speed for the Girbil type dongle. - * - */ - -#define GIRBIL_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) - -static int girbil_change_speed(struct sir_dev *dev, unsigned speed) -{ - unsigned state = dev->fsm.substate; - unsigned delay = 0; - u8 control[2]; - static int ret = 0; - - /* dongle alread reset - port and dongle at default speed */ - - switch(state) { - - case SIRDEV_STATE_DONGLE_SPEED: - - /* Set DTR and Clear RTS to enter command mode */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - - udelay(25); /* better wait a little while */ - - ret = 0; - switch (speed) { - default: - ret = -EINVAL; - /* fall through */ - case 9600: - control[0] = GIRBIL_9600; - break; - case 19200: - control[0] = GIRBIL_19200; - break; - case 34800: - control[0] = GIRBIL_38400; - break; - case 57600: - control[0] = GIRBIL_57600; - break; - case 115200: - control[0] = GIRBIL_115200; - break; - } - control[1] = GIRBIL_LOAD; - - /* Write control bytes */ - sirdev_raw_write(dev, control, 2); - - dev->speed = speed; - - state = GIRBIL_STATE_WAIT_SPEED; - delay = 100; - break; - - case GIRBIL_STATE_WAIT_SPEED: - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - udelay(25); /* better wait a little while */ - break; - - default: - net_err_ratelimited("%s - undefined state %d\n", - __func__, state); - ret = -EINVAL; - break; - } - dev->fsm.substate = state; - return (delay > 0) ? delay : ret; -} - -/* - * Function girbil_reset (driver) - * - * This function resets the girbil dongle. - * - * Algorithm: - * 0. set RTS, and wait at least 5 ms - * 1. clear RTS - */ - - -#define GIRBIL_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET + 1) -#define GIRBIL_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET + 2) -#define GIRBIL_STATE_WAIT3_RESET (SIRDEV_STATE_DONGLE_RESET + 3) - -static int girbil_reset(struct sir_dev *dev) -{ - unsigned state = dev->fsm.substate; - unsigned delay = 0; - u8 control = GIRBIL_TXEN | GIRBIL_RXEN; - int ret = 0; - - switch (state) { - case SIRDEV_STATE_DONGLE_RESET: - /* Reset dongle */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - /* Sleep at least 5 ms */ - delay = 20; - state = GIRBIL_STATE_WAIT1_RESET; - break; - - case GIRBIL_STATE_WAIT1_RESET: - /* Set DTR and clear RTS to enter command mode */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - delay = 20; - state = GIRBIL_STATE_WAIT2_RESET; - break; - - case GIRBIL_STATE_WAIT2_RESET: - /* Write control byte */ - sirdev_raw_write(dev, &control, 1); - delay = 20; - state = GIRBIL_STATE_WAIT3_RESET; - break; - - case GIRBIL_STATE_WAIT3_RESET: - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - dev->speed = 9600; - break; - - default: - net_err_ratelimited("%s(), undefined state %d\n", - __func__, state); - ret = -1; - break; - } - dev->fsm.substate = state; - return (delay > 0) ? delay : ret; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-4"); /* IRDA_GIRBIL_DONGLE */ - -module_init(girbil_sir_init); -module_exit(girbil_sir_cleanup); diff --git a/drivers/staging/irda/drivers/irda-usb.c b/drivers/staging/irda/drivers/irda-usb.c deleted file mode 100644 index bda6bdc6c70b..000000000000 --- a/drivers/staging/irda/drivers/irda-usb.c +++ /dev/null @@ -1,1906 +0,0 @@ -/***************************************************************************** - * - * Filename: irda-usb.c - * Version: 0.10 - * Description: IrDA-USB Driver - * Status: Experimental - * Author: Dag Brattli <dag@brattli.net> - * - * Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> - * Copyright (C) 2001, Dag Brattli <dag@brattli.net> - * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> - * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com> - * Copyright (C) 2005, Milan Beno <beno@pobox.sk> - * Copyright (C) 2006, Nick Fedchik <nick@fedchik.org.ua> - * - * 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. - * - *****************************************************************************/ - -/* - * IMPORTANT NOTE - * -------------- - * - * As of kernel 2.5.20, this is the state of compliance and testing of - * this driver (irda-usb) with regards to the USB low level drivers... - * - * This driver has been tested SUCCESSFULLY with the following drivers : - * o usb-uhci-hcd (For Intel/Via USB controllers) - * o uhci-hcd (Alternate/JE driver for Intel/Via USB controllers) - * o ohci-hcd (For other USB controllers) - * - * This driver has NOT been tested with the following drivers : - * o ehci-hcd (USB 2.0 controllers) - * - * Note that all HCD drivers do URB_ZERO_PACKET and timeout properly, - * so we don't have to worry about that anymore. - * One common problem is the failure to set the address on the dongle, - * but this happens before the driver gets loaded... - * - * Jean II - */ - -/*------------------------------------------------------------------*/ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/rtnetlink.h> -#include <linux/usb.h> -#include <linux/firmware.h> - -#include "irda-usb.h" - -/*------------------------------------------------------------------*/ - -static int qos_mtt_bits = 0; - -/* These are the currently known IrDA USB dongles. Add new dongles here */ -static const struct usb_device_id dongles[] = { - /* ACTiSYS Corp., ACT-IR2000U FIR-USB Adapter */ - { USB_DEVICE(0x9c4, 0x011), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, - /* Look like ACTiSYS, Report : IBM Corp., IBM UltraPort IrDA */ - { USB_DEVICE(0x4428, 0x012), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, - /* KC Technology Inc., KC-180 USB IrDA Device */ - { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, - /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ - { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, - /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */ - { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR421X | IUC_SPEED_BUG }, - { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR421X | IUC_SPEED_BUG }, - { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR421X | IUC_SPEED_BUG }, - { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .bInterfaceClass = USB_CLASS_APP_SPEC, - .bInterfaceSubClass = USB_CLASS_IRDA, - .driver_info = IUC_DEFAULT, }, - { }, /* The end */ -}; - -/* - * Important note : - * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not designed - * using the "USB-IrDA specification" (yes, there exist such a thing), and - * therefore not supported by this driver (don't add them above). - * There is a Linux driver, stir4200, that support those USB devices. - * Jean II - */ - -MODULE_DEVICE_TABLE(usb, dongles); - -/*------------------------------------------------------------------*/ - -static void irda_usb_init_qos(struct irda_usb_cb *self) ; -static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); -static void irda_usb_disconnect(struct usb_interface *intf); -static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); -static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, - struct net_device *dev); -static int irda_usb_open(struct irda_usb_cb *self); -static void irda_usb_close(struct irda_usb_cb *self); -static void speed_bulk_callback(struct urb *urb); -static void write_bulk_callback(struct urb *urb); -static void irda_usb_receive(struct urb *urb); -static void irda_usb_rx_defer_expired(struct timer_list *t); -static int irda_usb_net_open(struct net_device *dev); -static int irda_usb_net_close(struct net_device *dev); -static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void irda_usb_net_timeout(struct net_device *dev); - -/************************ TRANSMIT ROUTINES ************************/ -/* - * Receive packets from the IrDA stack and send them on the USB pipe. - * Handle speed change, timeout and lot's of ugliness... - */ - -/*------------------------------------------------------------------*/ -/* - * Function irda_usb_build_header(self, skb, header) - * - * Builds USB-IrDA outbound header - * - * When we send an IrDA frame over an USB pipe, we add to it a 1 byte - * header. This function create this header with the proper values. - * - * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2 - * that the setting of the link speed and xbof number in this outbound header - * should be applied *AFTER* the frame has been sent. - * Unfortunately, some devices are not compliant with that... It seems that - * reading the spec is far too difficult... - * Jean II - */ -static void irda_usb_build_header(struct irda_usb_cb *self, - __u8 *header, - int force) -{ - /* Here we check if we have an STIR421x chip, - * and if either speed or xbofs (or both) needs - * to be changed. - */ - if (self->capability & IUC_STIR421X && - ((self->new_speed != -1) || (self->new_xbofs != -1))) { - - /* With STIR421x, speed and xBOFs must be set at the same - * time, even if only one of them changes. - */ - if (self->new_speed == -1) - self->new_speed = self->speed ; - - if (self->new_xbofs == -1) - self->new_xbofs = self->xbofs ; - } - - /* Set the link speed */ - if (self->new_speed != -1) { - /* Hum... Ugly hack :-( - * Some device are not compliant with the spec and change - * parameters *before* sending the frame. - Jean II - */ - if ((self->capability & IUC_SPEED_BUG) && - (!force) && (self->speed != -1)) { - /* No speed and xbofs change here - * (we'll do it later in the write callback) */ - pr_debug("%s(), not changing speed yet\n", __func__); - *header = 0; - return; - } - - pr_debug("%s(), changing speed to %d\n", - __func__, self->new_speed); - self->speed = self->new_speed; - /* We will do ` self->new_speed = -1; ' in the completion - * handler just in case the current URB fail - Jean II */ - - switch (self->speed) { - case 2400: - *header = SPEED_2400; - break; - default: - case 9600: - *header = SPEED_9600; - break; - case 19200: - *header = SPEED_19200; - break; - case 38400: - *header = SPEED_38400; - break; - case 57600: - *header = SPEED_57600; - break; - case 115200: - *header = SPEED_115200; - break; - case 576000: - *header = SPEED_576000; - break; - case 1152000: - *header = SPEED_1152000; - break; - case 4000000: - *header = SPEED_4000000; - self->new_xbofs = 0; - break; - case 16000000: - *header = SPEED_16000000; - self->new_xbofs = 0; - break; - } - } else - /* No change */ - *header = 0; - - /* Set the negotiated additional XBOFS */ - if (self->new_xbofs != -1) { - pr_debug("%s(), changing xbofs to %d\n", - __func__, self->new_xbofs); - self->xbofs = self->new_xbofs; - /* We will do ` self->new_xbofs = -1; ' in the completion - * handler just in case the current URB fail - Jean II */ - - switch (self->xbofs) { - case 48: - *header |= 0x10; - break; - case 28: - case 24: /* USB spec 1.0 says 24 */ - *header |= 0x20; - break; - default: - case 12: - *header |= 0x30; - break; - case 5: /* Bug in IrLAP spec? (should be 6) */ - case 6: - *header |= 0x40; - break; - case 3: - *header |= 0x50; - break; - case 2: - *header |= 0x60; - break; - case 1: - *header |= 0x70; - break; - case 0: - *header |= 0x80; - break; - } - } -} - -/* -* calculate turnaround time for SigmaTel header -*/ -static __u8 get_turnaround_time(struct sk_buff *skb) -{ - int turnaround_time = irda_get_mtt(skb); - - if ( turnaround_time == 0 ) - return 0; - else if ( turnaround_time <= 10 ) - return 1; - else if ( turnaround_time <= 50 ) - return 2; - else if ( turnaround_time <= 100 ) - return 3; - else if ( turnaround_time <= 500 ) - return 4; - else if ( turnaround_time <= 1000 ) - return 5; - else if ( turnaround_time <= 5000 ) - return 6; - else - return 7; -} - - -/*------------------------------------------------------------------*/ -/* - * Send a command to change the speed of the dongle - * Need to be called with spinlock on. - */ -static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) -{ - __u8 *frame; - struct urb *urb; - int ret; - - pr_debug("%s(), speed=%d, xbofs=%d\n", __func__, - self->new_speed, self->new_xbofs); - - /* Grab the speed URB */ - urb = self->speed_urb; - if (urb->status != 0) { - net_warn_ratelimited("%s(), URB still in use!\n", __func__); - return; - } - - /* Allocate the fake frame */ - frame = self->speed_buff; - - /* Set the new speed and xbofs in this fake frame */ - irda_usb_build_header(self, frame, 1); - - if (self->capability & IUC_STIR421X) { - if (frame[0] == 0) return ; // do nothing if no change - frame[1] = 0; // other parameters don't change here - frame[2] = 0; - } - - /* Submit the 0 length IrDA frame to trigger new speed settings */ - usb_fill_bulk_urb(urb, self->usbdev, - usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), - frame, IRDA_USB_SPEED_MTU, - speed_bulk_callback, self); - urb->transfer_buffer_length = self->header_length; - urb->transfer_flags = 0; - - /* Irq disabled -> GFP_ATOMIC */ - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - net_warn_ratelimited("%s(), failed Speed URB\n", __func__); -} - -/*------------------------------------------------------------------*/ -/* - * Speed URB callback - * Now, we can only get called for the speed URB. - */ -static void speed_bulk_callback(struct urb *urb) -{ - struct irda_usb_cb *self = urb->context; - - /* We should always have a context */ - IRDA_ASSERT(self != NULL, return;); - /* We should always be called for the speed URB */ - IRDA_ASSERT(urb == self->speed_urb, return;); - - /* Check for timeout and other USB nasties */ - if (urb->status != 0) { - /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n", - __func__, urb->status, urb->transfer_flags); - - /* Don't do anything here, that might confuse the USB layer. - * Instead, we will wait for irda_usb_net_timeout(), the - * network layer watchdog, to fix the situation. - * Jean II */ - /* A reset of the dongle might be welcomed here - Jean II */ - return; - } - - /* urb is now available */ - //urb->status = 0; -> tested above - - /* New speed and xbof is now committed in hardware */ - self->new_speed = -1; - self->new_xbofs = -1; - - /* Allow the stack to send more packets */ - netif_wake_queue(self->netdev); -} - -/*------------------------------------------------------------------*/ -/* - * Send an IrDA frame to the USB dongle (for transmission) - */ -static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct irda_usb_cb *self = netdev_priv(netdev); - struct urb *urb = self->tx_urb; - unsigned long flags; - s32 speed; - s16 xbofs; - int res, mtt; - - pr_debug("%s() on %s\n", __func__, netdev->name); - - netif_stop_queue(netdev); - - /* Protect us from USB callbacks, net watchdog and else. */ - spin_lock_irqsave(&self->lock, flags); - - /* Check if the device is still there. - * We need to check self->present under the spinlock because - * of irda_usb_disconnect() is synchronous - Jean II */ - if (!self->present) { - pr_debug("%s(), Device is gone...\n", __func__); - goto drop; - } - - /* Check if we need to change the number of xbofs */ - xbofs = irda_get_next_xbofs(skb); - if ((xbofs != self->xbofs) && (xbofs != -1)) { - self->new_xbofs = xbofs; - } - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->speed) && (speed != -1)) { - /* Set the desired speed */ - self->new_speed = speed; - - /* Check for empty frame */ - if (!skb->len) { - /* IrLAP send us an empty frame to make us change the - * speed. Changing speed with the USB adapter is in - * fact sending an empty frame to the adapter, so we - * could just let the present function do its job. - * However, we would wait for min turn time, - * do an extra memcpy and increment packet counters... - * Jean II */ - irda_usb_change_speed_xbofs(self); - netif_trans_update(netdev); - /* Will netif_wake_queue() in callback */ - goto drop; - } - } - - if (urb->status != 0) { - net_warn_ratelimited("%s(), URB still in use!\n", __func__); - goto drop; - } - - skb_copy_from_linear_data(skb, self->tx_buff + self->header_length, skb->len); - - /* Change setting for next frame */ - if (self->capability & IUC_STIR421X) { - __u8 turnaround_time; - __u8* frame = self->tx_buff; - turnaround_time = get_turnaround_time( skb ); - irda_usb_build_header(self, frame, 0); - frame[2] = turnaround_time; - if ((skb->len != 0) && - ((skb->len % 128) == 0) && - ((skb->len % 512) != 0)) { - /* add extra byte for special SigmaTel feature */ - frame[1] = 1; - skb_put(skb, 1); - } else { - frame[1] = 0; - } - } else { - irda_usb_build_header(self, self->tx_buff, 0); - } - - /* FIXME: Make macro out of this one */ - ((struct irda_skb_cb *)skb->cb)->context = self; - - usb_fill_bulk_urb(urb, self->usbdev, - usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), - self->tx_buff, skb->len + self->header_length, - write_bulk_callback, skb); - - /* This flag (URB_ZERO_PACKET) indicates that what we send is not - * a continuous stream of data but separate packets. - * In this case, the USB layer will insert an empty USB frame (TD) - * after each of our packets that is exact multiple of the frame size. - * This is how the dongle will detect the end of packet - Jean II */ - urb->transfer_flags = URB_ZERO_PACKET; - - /* Generate min turn time. FIXME: can we do better than this? */ - /* Trying to a turnaround time at this level is trying to measure - * processor clock cycle with a wrist-watch, approximate at best... - * - * What we know is the last time we received a frame over USB. - * Due to latency over USB that depend on the USB load, we don't - * know when this frame was received over IrDA (a few ms before ?) - * Then, same story for our outgoing frame... - * - * In theory, the USB dongle is supposed to handle the turnaround - * by itself (spec 1.0, chater 4, page 6). Who knows ??? That's - * why this code is enabled only for dongles that doesn't meet - * the spec. - * Jean II */ - if (self->capability & IUC_NO_TURN) { - mtt = irda_get_mtt(skb); - if (mtt) { - int diff; - diff = ktime_us_delta(ktime_get(), self->stamp); -#ifdef IU_USB_MIN_RTT - /* Factor in USB delays -> Get rid of udelay() that - * would be lost in the noise - Jean II */ - diff += IU_USB_MIN_RTT; -#endif /* IU_USB_MIN_RTT */ - - /* Check if the mtt is larger than the time we have - * already used by all the protocol processing - */ - if (mtt > diff) { - mtt -= diff; - if (mtt > 1000) - mdelay(mtt/1000); - else - udelay(mtt); - } - } - } - - /* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */ - if ((res = usb_submit_urb(urb, GFP_ATOMIC))) { - net_warn_ratelimited("%s(), failed Tx URB\n", __func__); - netdev->stats.tx_errors++; - /* Let USB recover : We will catch that in the watchdog */ - /*netif_start_queue(netdev);*/ - } else { - /* Increment packet stats */ - netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; - - netif_trans_update(netdev); - } - spin_unlock_irqrestore(&self->lock, flags); - - return NETDEV_TX_OK; - -drop: - /* Drop silently the skb and exit */ - dev_kfree_skb(skb); - spin_unlock_irqrestore(&self->lock, flags); - return NETDEV_TX_OK; -} - -/*------------------------------------------------------------------*/ -/* - * Note : this function will be called only for tx_urb... - */ -static void write_bulk_callback(struct urb *urb) -{ - unsigned long flags; - struct sk_buff *skb = urb->context; - struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context; - - /* We should always have a context */ - IRDA_ASSERT(self != NULL, return;); - /* We should always be called for the speed URB */ - IRDA_ASSERT(urb == self->tx_urb, return;); - - /* Free up the skb */ - dev_kfree_skb_any(skb); - urb->context = NULL; - - /* Check for timeout and other USB nasties */ - if (urb->status != 0) { - /* I get a lot of -ECONNABORTED = -103 here - Jean II */ - pr_debug("%s(), URB complete status %d, transfer_flags 0x%04X\n", - __func__, urb->status, urb->transfer_flags); - - /* Don't do anything here, that might confuse the USB layer, - * and we could go in recursion and blow the kernel stack... - * Instead, we will wait for irda_usb_net_timeout(), the - * network layer watchdog, to fix the situation. - * Jean II */ - /* A reset of the dongle might be welcomed here - Jean II */ - return; - } - - /* urb is now available */ - //urb->status = 0; -> tested above - - /* Make sure we read self->present properly */ - spin_lock_irqsave(&self->lock, flags); - - /* If the network is closed, stop everything */ - if ((!self->netopen) || (!self->present)) { - pr_debug("%s(), Network is gone...\n", __func__); - spin_unlock_irqrestore(&self->lock, flags); - return; - } - - /* If changes to speed or xbofs is pending... */ - if ((self->new_speed != -1) || (self->new_xbofs != -1)) { - if ((self->new_speed != self->speed) || - (self->new_xbofs != self->xbofs)) { - /* We haven't changed speed yet (because of - * IUC_SPEED_BUG), so do it now - Jean II */ - pr_debug("%s(), Changing speed now...\n", __func__); - irda_usb_change_speed_xbofs(self); - } else { - /* New speed and xbof is now committed in hardware */ - self->new_speed = -1; - self->new_xbofs = -1; - /* Done, waiting for next packet */ - netif_wake_queue(self->netdev); - } - } else { - /* Otherwise, allow the stack to send more packets */ - netif_wake_queue(self->netdev); - } - spin_unlock_irqrestore(&self->lock, flags); -} - -/*------------------------------------------------------------------*/ -/* - * Watchdog timer from the network layer. - * After a predetermined timeout, if we don't give confirmation that - * the packet has been sent (i.e. no call to netif_wake_queue()), - * the network layer will call this function. - * Note that URB that we submit have also a timeout. When the URB timeout - * expire, the normal URB callback is called (write_bulk_callback()). - */ -static void irda_usb_net_timeout(struct net_device *netdev) -{ - unsigned long flags; - struct irda_usb_cb *self = netdev_priv(netdev); - struct urb *urb; - int done = 0; /* If we have made any progress */ - - pr_debug("%s(), Network layer thinks we timed out!\n", __func__); - IRDA_ASSERT(self != NULL, return;); - - /* Protect us from USB callbacks, net Tx and else. */ - spin_lock_irqsave(&self->lock, flags); - - /* self->present *MUST* be read under spinlock */ - if (!self->present) { - net_warn_ratelimited("%s(), device not present!\n", __func__); - netif_stop_queue(netdev); - spin_unlock_irqrestore(&self->lock, flags); - return; - } - - /* Check speed URB */ - urb = self->speed_urb; - if (urb->status != 0) { - pr_debug("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", - netdev->name, urb->status, urb->transfer_flags); - - switch (urb->status) { - case -EINPROGRESS: - usb_unlink_urb(urb); - /* Note : above will *NOT* call netif_wake_queue() - * in completion handler, we will come back here. - * Jean II */ - done = 1; - break; - case -ECONNRESET: - case -ENOENT: /* urb unlinked by us */ - default: /* ??? - Play safe */ - urb->status = 0; - netif_wake_queue(self->netdev); - done = 1; - break; - } - } - - /* Check Tx URB */ - urb = self->tx_urb; - if (urb->status != 0) { - struct sk_buff *skb = urb->context; - - pr_debug("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", - netdev->name, urb->status, urb->transfer_flags); - - /* Increase error count */ - netdev->stats.tx_errors++; - -#ifdef IU_BUG_KICK_TIMEOUT - /* Can't be a bad idea to reset the speed ;-) - Jean II */ - if(self->new_speed == -1) - self->new_speed = self->speed; - if(self->new_xbofs == -1) - self->new_xbofs = self->xbofs; - irda_usb_change_speed_xbofs(self); -#endif /* IU_BUG_KICK_TIMEOUT */ - - switch (urb->status) { - case -EINPROGRESS: - usb_unlink_urb(urb); - /* Note : above will *NOT* call netif_wake_queue() - * in completion handler, because urb->status will - * be -ENOENT. We will fix that at the next watchdog, - * leaving more time to USB to recover... - * Jean II */ - done = 1; - break; - case -ECONNRESET: - case -ENOENT: /* urb unlinked by us */ - default: /* ??? - Play safe */ - if(skb != NULL) { - dev_kfree_skb_any(skb); - urb->context = NULL; - } - urb->status = 0; - netif_wake_queue(self->netdev); - done = 1; - break; - } - } - spin_unlock_irqrestore(&self->lock, flags); - - /* Maybe we need a reset */ - /* Note : Some drivers seem to use a usb_set_interface() when they - * need to reset the hardware. Hum... - */ - - /* if(done == 0) */ -} - -/************************* RECEIVE ROUTINES *************************/ -/* - * Receive packets from the USB layer stack and pass them to the IrDA stack. - * Try to work around USB failures... - */ - -/* - * Note : - * Some of you may have noticed that most dongle have an interrupt in pipe - * that we don't use. Here is the little secret... - * When we hang a Rx URB on the bulk in pipe, it generates some USB traffic - * in every USB frame. This is unnecessary overhead. - * The interrupt in pipe will generate an event every time a packet is - * received. Reading an interrupt pipe adds minimal overhead, but has some - * latency (~1ms). - * If we are connected (speed != 9600), we want to minimise latency, so - * we just always hang the Rx URB and ignore the interrupt. - * If we are not connected (speed == 9600), there is usually no Rx traffic, - * and we want to minimise the USB overhead. In this case we should wait - * on the interrupt pipe and hang the Rx URB only when an interrupt is - * received. - * Jean II - * - * Note : don't read the above as what we are currently doing, but as - * something we could do with KC dongle. Also don't forget that the - * interrupt pipe is not part of the original standard, so this would - * need to be optional... - * Jean II - */ - -/*------------------------------------------------------------------*/ -/* - * Submit a Rx URB to the USB layer to handle reception of a frame - * Mostly called by the completion callback of the previous URB. - * - * Jean II - */ -static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb) -{ - struct irda_skb_cb *cb; - int ret; - - /* This should never happen */ - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(urb != NULL, return;); - - /* Save ourselves in the skb */ - cb = (struct irda_skb_cb *) skb->cb; - cb->context = self; - - /* Reinitialize URB */ - usb_fill_bulk_urb(urb, self->usbdev, - usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), - skb->data, IRDA_SKB_MAX_MTU, - irda_usb_receive, skb); - urb->status = 0; - - /* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */ - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - /* If this ever happen, we are in deep s***. - * Basically, the Rx path will stop... */ - net_warn_ratelimited("%s(), Failed to submit Rx URB %d\n", - __func__, ret); - } -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_usb_receive(urb) - * - * Called by the USB subsystem when a frame has been received - * - */ -static void irda_usb_receive(struct urb *urb) -{ - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct irda_usb_cb *self; - struct irda_skb_cb *cb; - struct sk_buff *newskb; - struct sk_buff *dataskb; - struct urb *next_urb; - unsigned int len, docopy; - - pr_debug("%s(), len=%d\n", __func__, urb->actual_length); - - /* Find ourselves */ - cb = (struct irda_skb_cb *) skb->cb; - IRDA_ASSERT(cb != NULL, return;); - self = (struct irda_usb_cb *) cb->context; - IRDA_ASSERT(self != NULL, return;); - - /* If the network is closed or the device gone, stop everything */ - if ((!self->netopen) || (!self->present)) { - pr_debug("%s(), Network is gone!\n", __func__); - /* Don't re-submit the URB : will stall the Rx path */ - return; - } - - /* Check the status */ - if (urb->status != 0) { - switch (urb->status) { - case -EILSEQ: - self->netdev->stats.rx_crc_errors++; - /* Also precursor to a hot-unplug on UHCI. */ - /* Fallthrough... */ - case -ECONNRESET: - /* Random error, if I remember correctly */ - /* uhci_cleanup_unlink() is going to kill the Rx - * URB just after we return. No problem, at this - * point the URB will be idle ;-) - Jean II */ - case -ESHUTDOWN: - /* That's usually a hot-unplug. Submit will fail... */ - case -ETIME: - /* Usually precursor to a hot-unplug on OHCI. */ - default: - self->netdev->stats.rx_errors++; - pr_debug("%s(), RX status %d, transfer_flags 0x%04X\n", - __func__, urb->status, urb->transfer_flags); - break; - } - /* If we received an error, we don't want to resubmit the - * Rx URB straight away but to give the USB layer a little - * bit of breathing room. - * We are in the USB thread context, therefore there is a - * danger of recursion (new URB we submit fails, we come - * back here). - * With recent USB stack (2.6.15+), I'm seeing that on - * hot unplug of the dongle... - * Lowest effective timer is 10ms... - * Jean II */ - self->rx_defer_timer_urb = urb; - mod_timer(&self->rx_defer_timer, - jiffies + msecs_to_jiffies(10)); - - return; - } - - /* Check for empty frames */ - if (urb->actual_length <= self->header_length) { - net_warn_ratelimited("%s(), empty frame!\n", __func__); - goto done; - } - - /* - * Remember the time we received this frame, so we can - * reduce the min turn time a bit since we will know - * how much time we have used for protocol processing - */ - self->stamp = ktime_get(); - - /* Check if we need to copy the data to a new skb or not. - * For most frames, we use ZeroCopy and pass the already - * allocated skb up the stack. - * If the frame is small, it is more efficient to copy it - * to save memory (copy will be fast anyway - that's - * called Rx-copy-break). Jean II */ - docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); - - /* Allocate a new skb */ - if (self->capability & IUC_STIR421X) - newskb = dev_alloc_skb(docopy ? urb->actual_length : - IRDA_SKB_MAX_MTU + - USB_IRDA_STIR421X_HEADER); - else - newskb = dev_alloc_skb(docopy ? urb->actual_length : - IRDA_SKB_MAX_MTU); - - if (!newskb) { - self->netdev->stats.rx_dropped++; - /* We could deliver the current skb, but this would stall - * the Rx path. Better drop the packet... Jean II */ - goto done; - } - - /* Make sure IP header get aligned (IrDA header is 5 bytes) */ - /* But IrDA-USB header is 1 byte. Jean II */ - //skb_reserve(newskb, USB_IRDA_HEADER - 1); - - if(docopy) { - /* Copy packet, so we can recycle the original */ - skb_copy_from_linear_data(skb, newskb->data, urb->actual_length); - /* Deliver this new skb */ - dataskb = newskb; - /* And hook the old skb to the URB - * Note : we don't need to "clean up" the old skb, - * as we never touched it. Jean II */ - } else { - /* We are using ZeroCopy. Deliver old skb */ - dataskb = skb; - /* And hook the new skb to the URB */ - skb = newskb; - } - - /* Set proper length on skb & remove USB-IrDA header */ - skb_put(dataskb, urb->actual_length); - skb_pull(dataskb, self->header_length); - - /* Ask the networking layer to queue the packet for the IrDA stack */ - dataskb->dev = self->netdev; - skb_reset_mac_header(dataskb); - dataskb->protocol = htons(ETH_P_IRDA); - len = dataskb->len; - netif_rx(dataskb); - - /* Keep stats up to date */ - self->netdev->stats.rx_bytes += len; - self->netdev->stats.rx_packets++; - -done: - /* Note : at this point, the URB we've just received (urb) - * is still referenced by the USB layer. For example, if we - * have received a -ECONNRESET, uhci_cleanup_unlink() will - * continue to process it (in fact, cleaning it up). - * If we were to submit this URB, disaster would ensue. - * Therefore, we submit our idle URB, and put this URB in our - * idle slot.... - * Jean II */ - /* Note : with this scheme, we could submit the idle URB before - * processing the Rx URB. I don't think it would buy us anything as - * we are running in the USB thread context. Jean II */ - next_urb = self->idle_rx_urb; - - /* Recycle Rx URB : Now, the idle URB is the present one */ - urb->context = NULL; - self->idle_rx_urb = urb; - - /* Submit the idle URB to replace the URB we've just received. - * Do it last to avoid race conditions... Jean II */ - irda_usb_submit(self, skb, next_urb); -} - -/*------------------------------------------------------------------*/ -/* - * In case of errors, we want the USB layer to have time to recover. - * Now, it is time to resubmit ouur Rx URB... - */ -static void irda_usb_rx_defer_expired(struct timer_list *t) -{ - struct irda_usb_cb *self = from_timer(self, t, rx_defer_timer); - struct urb *urb = self->rx_defer_timer_urb; - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct urb *next_urb; - - /* Same stuff as when Rx is done, see above... */ - next_urb = self->idle_rx_urb; - urb->context = NULL; - self->idle_rx_urb = urb; - irda_usb_submit(self, skb, next_urb); -} - -/*------------------------------------------------------------------*/ -/* - * Callbak from IrDA layer. IrDA wants to know if we have - * started receiving anything. - */ -static int irda_usb_is_receiving(struct irda_usb_cb *self) -{ - /* Note : because of the way UHCI works, it's almost impossible - * to get this info. The Controller DMA directly to memory and - * signal only when the whole frame is finished. To know if the - * first TD of the URB has been filled or not seems hard work... - * - * The other solution would be to use the "receiving" command - * on the default decriptor with a usb_control_msg(), but that - * would add USB traffic and would return result only in the - * next USB frame (~1ms). - * - * I've been told that current dongles send status info on their - * interrupt endpoint, and that's what the Windows driver uses - * to know this info. Unfortunately, this is not yet in the spec... - * - * Jean II - */ - - return 0; /* For now */ -} - -#define STIR421X_PATCH_PRODUCT_VER "Product Version: " -#define STIR421X_PATCH_STMP_TAG "STMP" -#define STIR421X_PATCH_CODE_OFFSET 512 /* patch image starts before here */ -/* marks end of patch file header (PC DOS text file EOF character) */ -#define STIR421X_PATCH_END_OF_HDR_TAG 0x1A -#define STIR421X_PATCH_BLOCK_SIZE 1023 - -/* - * Function stir421x_fwupload (struct irda_usb_cb *self, - * unsigned char *patch, - * const unsigned int patch_len) - * - * Upload firmware code to SigmaTel 421X IRDA-USB dongle - */ -static int stir421x_fw_upload(struct irda_usb_cb *self, - const unsigned char *patch, - const unsigned int patch_len) -{ - int ret = -ENOMEM; - int actual_len = 0; - unsigned int i; - unsigned int block_size = 0; - unsigned char *patch_block; - - patch_block = kzalloc(STIR421X_PATCH_BLOCK_SIZE, GFP_KERNEL); - if (patch_block == NULL) - return -ENOMEM; - - /* break up patch into 1023-byte sections */ - for (i = 0; i < patch_len; i += block_size) { - block_size = patch_len - i; - - if (block_size > STIR421X_PATCH_BLOCK_SIZE) - block_size = STIR421X_PATCH_BLOCK_SIZE; - - /* upload the patch section */ - memcpy(patch_block, patch + i, block_size); - - ret = usb_bulk_msg(self->usbdev, - usb_sndbulkpipe(self->usbdev, - self->bulk_out_ep), - patch_block, block_size, - &actual_len, msecs_to_jiffies(500)); - pr_debug("%s(): Bulk send %u bytes, ret=%d\n", - __func__, actual_len, ret); - - if (ret < 0) - break; - - mdelay(10); - } - - kfree(patch_block); - - return ret; - } - -/* - * Function stir421x_patch_device(struct irda_usb_cb *self) - * - * Get a firmware code from userspase using hotplug request_firmware() call - */ -static int stir421x_patch_device(struct irda_usb_cb *self) -{ - unsigned int i; - int ret; - char stir421x_fw_name[12]; - const struct firmware *fw; - const unsigned char *fw_version_ptr; /* pointer to version string */ - unsigned long fw_version = 0; - - /* - * Known firmware patch file names for STIR421x dongles - * are "42101001.sb" or "42101002.sb" - */ - sprintf(stir421x_fw_name, "4210%4X.sb", - le16_to_cpu(self->usbdev->descriptor.bcdDevice)); - ret = request_firmware(&fw, stir421x_fw_name, &self->usbdev->dev); - if (ret < 0) - return ret; - - /* We get a patch from userspace */ - net_info_ratelimited("%s(): Received firmware %s (%zu bytes)\n", - __func__, stir421x_fw_name, fw->size); - - ret = -EINVAL; - - /* Get the bcd product version */ - if (!memcmp(fw->data, STIR421X_PATCH_PRODUCT_VER, - sizeof(STIR421X_PATCH_PRODUCT_VER) - 1)) { - fw_version_ptr = fw->data + - sizeof(STIR421X_PATCH_PRODUCT_VER) - 1; - - /* Let's check if the product version is dotted */ - if (fw_version_ptr[3] == '.' && - fw_version_ptr[7] == '.') { - unsigned long major, minor, build; - major = simple_strtoul(fw_version_ptr, NULL, 10); - minor = simple_strtoul(fw_version_ptr + 4, NULL, 10); - build = simple_strtoul(fw_version_ptr + 8, NULL, 10); - - fw_version = (major << 12) - + (minor << 8) - + ((build / 10) << 4) - + (build % 10); - - pr_debug("%s(): Firmware Product version %ld\n", - __func__, fw_version); - } - } - - if (self->usbdev->descriptor.bcdDevice == cpu_to_le16(fw_version)) { - /* - * If we're here, we've found a correct patch - * The actual image starts after the "STMP" keyword - * so forward to the firmware header tag - */ - for (i = 0; i < fw->size && fw->data[i] != - STIR421X_PATCH_END_OF_HDR_TAG; i++) ; - /* here we check for the out of buffer case */ - if (i < STIR421X_PATCH_CODE_OFFSET && i < fw->size && - STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) { - if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG, - sizeof(STIR421X_PATCH_STMP_TAG) - 1)) { - - /* We can upload the patch to the target */ - i += sizeof(STIR421X_PATCH_STMP_TAG); - ret = stir421x_fw_upload(self, &fw->data[i], - fw->size - i); - } - } - } - - release_firmware(fw); - - return ret; -} - - -/********************** IRDA DEVICE CALLBACKS **********************/ -/* - * Main calls from the IrDA/Network subsystem. - * Mostly registering a new irda-usb device and removing it.... - * We only deal with the IrDA side of the business, the USB side will - * be dealt with below... - */ - - -/*------------------------------------------------------------------*/ -/* - * Function irda_usb_net_open (dev) - * - * Network device is taken up. Usually this is done by "ifconfig irda0 up" - * - * Note : don't mess with self->netopen - Jean II - */ -static int irda_usb_net_open(struct net_device *netdev) -{ - struct irda_usb_cb *self; - unsigned long flags; - char hwname[16]; - int i; - - IRDA_ASSERT(netdev != NULL, return -1;); - self = netdev_priv(netdev); - IRDA_ASSERT(self != NULL, return -1;); - - spin_lock_irqsave(&self->lock, flags); - /* Can only open the device if it's there */ - if(!self->present) { - spin_unlock_irqrestore(&self->lock, flags); - net_warn_ratelimited("%s(), device not present!\n", __func__); - return -1; - } - - if(self->needspatch) { - spin_unlock_irqrestore(&self->lock, flags); - net_warn_ratelimited("%s(), device needs patch\n", __func__); - return -EIO ; - } - - /* Initialise default speed and xbofs value - * (IrLAP will change that soon) */ - self->speed = -1; - self->xbofs = -1; - self->new_speed = -1; - self->new_xbofs = -1; - - /* To do *before* submitting Rx urbs and starting net Tx queue - * Jean II */ - self->netopen = 1; - spin_unlock_irqrestore(&self->lock, flags); - - /* - * Now that everything should be initialized properly, - * Open new IrLAP layer instance to take care of us... - * Note : will send immediately a speed change... - */ - sprintf(hwname, "usb#%d", self->usbdev->devnum); - self->irlap = irlap_open(netdev, &self->qos, hwname); - IRDA_ASSERT(self->irlap != NULL, return -1;); - - /* Allow IrLAP to send data to us */ - netif_start_queue(netdev); - - /* We submit all the Rx URB except for one that we keep idle. - * Need to be initialised before submitting other USBs, because - * in some cases as soon as we submit the URBs the USB layer - * will trigger a dummy receive - Jean II */ - self->idle_rx_urb = self->rx_urb[IU_MAX_ACTIVE_RX_URBS]; - self->idle_rx_urb->context = NULL; - - /* Now that we can pass data to IrLAP, allow the USB layer - * to send us some data... */ - for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) { - struct sk_buff *skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (!skb) { - /* If this ever happen, we are in deep s***. - * Basically, we can't start the Rx path... */ - return -1; - } - //skb_reserve(newskb, USB_IRDA_HEADER - 1); - irda_usb_submit(self, skb, self->rx_urb[i]); - } - - /* Ready to play !!! */ - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_usb_net_close (self) - * - * Network device is taken down. Usually this is done by - * "ifconfig irda0 down" - */ -static int irda_usb_net_close(struct net_device *netdev) -{ - struct irda_usb_cb *self; - int i; - - IRDA_ASSERT(netdev != NULL, return -1;); - self = netdev_priv(netdev); - IRDA_ASSERT(self != NULL, return -1;); - - /* Clear this flag *before* unlinking the urbs and *before* - * stopping the network Tx queue - Jean II */ - self->netopen = 0; - - /* Stop network Tx queue */ - netif_stop_queue(netdev); - - /* Kill defered Rx URB */ - del_timer(&self->rx_defer_timer); - - /* Deallocate all the Rx path buffers (URBs and skb) */ - for (i = 0; i < self->max_rx_urb; i++) { - struct urb *urb = self->rx_urb[i]; - struct sk_buff *skb = (struct sk_buff *) urb->context; - /* Cancel the receive command */ - usb_kill_urb(urb); - /* The skb is ours, free it */ - if(skb) { - dev_kfree_skb(skb); - urb->context = NULL; - } - } - /* Cancel Tx and speed URB - need to be synchronous to avoid races */ - usb_kill_urb(self->tx_urb); - usb_kill_urb(self->speed_urb); - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * IOCTLs : Extra out-of-band network commands... - */ -static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - unsigned long flags; - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct irda_usb_cb *self; - int ret = 0; - - IRDA_ASSERT(dev != NULL, return -1;); - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return -1;); - - pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* Protect us from USB callbacks, net watchdog and else. */ - spin_lock_irqsave(&self->lock, flags); - /* Check if the device is still there */ - if(self->present) { - /* Set the desired speed */ - self->new_speed = irq->ifr_baudrate; - irda_usb_change_speed_xbofs(self); - } - spin_unlock_irqrestore(&self->lock, flags); - break; - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* Check if the IrDA stack is still there */ - if(self->netopen) - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = irda_usb_is_receiving(self); - break; - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -/*------------------------------------------------------------------*/ - -/********************* IRDA CONFIG SUBROUTINES *********************/ -/* - * Various subroutines dealing with IrDA and network stuff we use to - * configure and initialise each irda-usb instance. - * These functions are used below in the main calls of the driver... - */ - -/*------------------------------------------------------------------*/ -/* - * Set proper values in the IrDA QOS structure - */ -static inline void irda_usb_init_qos(struct irda_usb_cb *self) -{ - struct irda_class_desc *desc; - - - desc = self->irda_desc; - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - /* See spec section 7.2 for meaning. - * Values are little endian (as most USB stuff), the IrDA stack - * use it in native order (see parameters.c). - Jean II */ - self->qos.baud_rate.bits = le16_to_cpu(desc->wBaudRate); - self->qos.min_turn_time.bits = desc->bmMinTurnaroundTime; - self->qos.additional_bofs.bits = desc->bmAdditionalBOFs; - self->qos.window_size.bits = desc->bmWindowSize; - self->qos.data_size.bits = desc->bmDataSize; - - pr_debug("%s(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", - __func__, self->qos.baud_rate.bits, self->qos.data_size.bits, - self->qos.window_size.bits, self->qos.additional_bofs.bits, - self->qos.min_turn_time.bits); - - /* Don't always trust what the dongle tell us */ - if(self->capability & IUC_SIR_ONLY) - self->qos.baud_rate.bits &= 0x00ff; - if(self->capability & IUC_SMALL_PKT) - self->qos.data_size.bits = 0x07; - if(self->capability & IUC_NO_WINDOW) - self->qos.window_size.bits = 0x01; - if(self->capability & IUC_MAX_WINDOW) - self->qos.window_size.bits = 0x7f; - if(self->capability & IUC_MAX_XBOFS) - self->qos.additional_bofs.bits = 0x01; - -#if 1 - /* Module parameter can override the rx window size */ - if (qos_mtt_bits) - self->qos.min_turn_time.bits = qos_mtt_bits; -#endif - /* - * Note : most of those values apply only for the receive path, - * the transmit path will be set differently - Jean II - */ - irda_qos_bits_to_value(&self->qos); -} - -/*------------------------------------------------------------------*/ -static const struct net_device_ops irda_usb_netdev_ops = { - .ndo_open = irda_usb_net_open, - .ndo_stop = irda_usb_net_close, - .ndo_do_ioctl = irda_usb_net_ioctl, - .ndo_start_xmit = irda_usb_hard_xmit, - .ndo_tx_timeout = irda_usb_net_timeout, -}; - -/* - * Initialise the network side of the irda-usb instance - * Called when a new USB instance is registered in irda_usb_probe() - */ -static inline int irda_usb_open(struct irda_usb_cb *self) -{ - struct net_device *netdev = self->netdev; - - netdev->netdev_ops = &irda_usb_netdev_ops; - - irda_usb_init_qos(self); - - return register_netdev(netdev); -} - -/*------------------------------------------------------------------*/ -/* - * Cleanup the network side of the irda-usb instance - * Called when a USB instance is removed in irda_usb_disconnect() - */ -static inline void irda_usb_close(struct irda_usb_cb *self) -{ - /* Remove netdevice */ - unregister_netdev(self->netdev); - - /* Remove the speed buffer */ - kfree(self->speed_buff); - self->speed_buff = NULL; - - kfree(self->tx_buff); - self->tx_buff = NULL; -} - -/********************** USB CONFIG SUBROUTINES **********************/ -/* - * Various subroutines dealing with USB stuff we use to configure and - * initialise each irda-usb instance. - * These functions are used below in the main calls of the driver... - */ - -/*------------------------------------------------------------------*/ -/* - * Function irda_usb_parse_endpoints(dev, ifnum) - * - * Parse the various endpoints and find the one we need. - * - * The endpoint are the pipes used to communicate with the USB device. - * The spec defines 2 endpoints of type bulk transfer, one in, and one out. - * These are used to pass frames back and forth with the dongle. - * Most dongle have also an interrupt endpoint, that will be probably - * documented in the next spec... - */ -static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_host_endpoint *endpoint, int ennum) -{ - int i; /* Endpoint index in table */ - - /* Init : no endpoints */ - self->bulk_in_ep = 0; - self->bulk_out_ep = 0; - self->bulk_int_ep = 0; - - /* Let's look at all those endpoints */ - for(i = 0; i < ennum; i++) { - /* All those variables will get optimised by the compiler, - * so let's aim for clarity... - Jean II */ - __u8 ep; /* Endpoint address */ - __u8 dir; /* Endpoint direction */ - __u8 attr; /* Endpoint attribute */ - __u16 psize; /* Endpoint max packet size in bytes */ - - /* Get endpoint address, direction and attribute */ - ep = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - dir = endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK; - attr = endpoint[i].desc.bmAttributes; - psize = le16_to_cpu(endpoint[i].desc.wMaxPacketSize); - - /* Is it a bulk endpoint ??? */ - if(attr == USB_ENDPOINT_XFER_BULK) { - /* We need to find an IN and an OUT */ - if(dir == USB_DIR_IN) { - /* This is our Rx endpoint */ - self->bulk_in_ep = ep; - } else { - /* This is our Tx endpoint */ - self->bulk_out_ep = ep; - self->bulk_out_mtu = psize; - } - } else { - if((attr == USB_ENDPOINT_XFER_INT) && - (dir == USB_DIR_IN)) { - /* This is our interrupt endpoint */ - self->bulk_int_ep = ep; - } else { - net_err_ratelimited("%s(), Unrecognised endpoint %02X\n", - __func__, ep); - } - } - } - - pr_debug("%s(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", - __func__, self->bulk_in_ep, self->bulk_out_ep, - self->bulk_out_mtu, self->bulk_int_ep); - - return (self->bulk_in_ep != 0) && (self->bulk_out_ep != 0); -} - -#ifdef IU_DUMP_CLASS_DESC -/*------------------------------------------------------------------*/ -/* - * Function usb_irda_dump_class_desc(desc) - * - * Prints out the contents of the IrDA class descriptor - * - */ -static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc) -{ - /* Values are little endian */ - printk("bLength=%x\n", desc->bLength); - printk("bDescriptorType=%x\n", desc->bDescriptorType); - printk("bcdSpecRevision=%x\n", le16_to_cpu(desc->bcdSpecRevision)); - printk("bmDataSize=%x\n", desc->bmDataSize); - printk("bmWindowSize=%x\n", desc->bmWindowSize); - printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); - printk("wBaudRate=%x\n", le16_to_cpu(desc->wBaudRate)); - printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); - printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); - printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList); -} -#endif /* IU_DUMP_CLASS_DESC */ - -/*------------------------------------------------------------------*/ -/* - * Function irda_usb_find_class_desc(intf) - * - * Returns instance of IrDA class descriptor, or NULL if not found - * - * The class descriptor is some extra info that IrDA USB devices will - * offer to us, describing their IrDA characteristics. We will use that in - * irda_usb_init_qos() - */ -static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf) -{ - struct usb_device *dev = interface_to_usbdev (intf); - struct irda_class_desc *desc; - int ret; - - desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) - return NULL; - - /* USB-IrDA class spec 1.0: - * 6.1.3: Standard "Get Descriptor" Device Request is not - * appropriate to retrieve class-specific descriptor - * 6.2.5: Class Specific "Get Class Descriptor" Interface Request - * is mandatory and returns the USB-IrDA class descriptor - */ - - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0), - IU_REQ_GET_CLASS_DESC, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, intf->altsetting->desc.bInterfaceNumber, desc, - sizeof(*desc), 500); - - pr_debug("%s(), ret=%d\n", __func__, ret); - if (ret < sizeof(*desc)) { - net_warn_ratelimited("usb-irda: class_descriptor read %s (%d)\n", - ret < 0 ? "failed" : "too short", ret); - } - else if (desc->bDescriptorType != USB_DT_IRDA) { - net_warn_ratelimited("usb-irda: bad class_descriptor type\n"); - } - else { -#ifdef IU_DUMP_CLASS_DESC - irda_usb_dump_class_desc(desc); -#endif /* IU_DUMP_CLASS_DESC */ - - return desc; - } - kfree(desc); - return NULL; -} - -/*********************** USB DEVICE CALLBACKS ***********************/ -/* - * Main calls from the USB subsystem. - * Mostly registering a new irda-usb device and removing it.... - */ - -/*------------------------------------------------------------------*/ -/* - * This routine is called by the USB subsystem for each new device - * in the system. We need to check if the device is ours, and in - * this case start handling it. - * The USB layer protect us from reentrancy (via BKL), so we don't need - * to spinlock in there... Jean II - */ -static int irda_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct net_device *net; - struct usb_device *dev = interface_to_usbdev(intf); - struct irda_usb_cb *self; - struct usb_host_interface *interface; - struct irda_class_desc *irda_desc; - int ret = -ENOMEM; - int i; /* Driver instance index / Rx URB index */ - - /* Note : the probe make sure to call us only for devices that - * matches the list of dongle (top of the file). So, we - * don't need to check if the dongle is really ours. - * Jean II */ - - net_info_ratelimited("IRDA-USB found at address %d, Vendor: %x, Product: %x\n", - dev->devnum, le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - net = alloc_irdadev(sizeof(*self)); - if (!net) - goto err_out; - - SET_NETDEV_DEV(net, &intf->dev); - self = netdev_priv(net); - self->netdev = net; - spin_lock_init(&self->lock); - timer_setup(&self->rx_defer_timer, irda_usb_rx_defer_expired, 0); - - self->capability = id->driver_info; - self->needspatch = ((self->capability & IUC_STIR421X) != 0); - - /* Create all of the needed urbs */ - if (self->capability & IUC_STIR421X) { - self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS; - self->header_length = USB_IRDA_STIR421X_HEADER; - } else { - self->max_rx_urb = IU_MAX_RX_URBS; - self->header_length = USB_IRDA_HEADER; - } - - self->rx_urb = kcalloc(self->max_rx_urb, sizeof(struct urb *), - GFP_KERNEL); - if (!self->rx_urb) - goto err_free_net; - - for (i = 0; i < self->max_rx_urb; i++) { - self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!self->rx_urb[i]) { - goto err_out_1; - } - } - self->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!self->tx_urb) { - goto err_out_1; - } - self->speed_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!self->speed_urb) { - goto err_out_2; - } - - /* Is this really necessary? (no, except maybe for broken devices) */ - if (usb_reset_configuration (dev) < 0) { - dev_err(&intf->dev, "reset_configuration failed\n"); - ret = -EIO; - goto err_out_3; - } - - /* Is this really necessary? */ - /* Note : some driver do hardcode the interface number, some others - * specify an alternate, but very few driver do like this. - * Jean II */ - ret = usb_set_interface(dev, intf->altsetting->desc.bInterfaceNumber, 0); - pr_debug("usb-irda: set interface %d result %d\n", - intf->altsetting->desc.bInterfaceNumber, ret); - switch (ret) { - case 0: - break; - case -EPIPE: /* -EPIPE = -32 */ - /* Martin Diehl says if we get a -EPIPE we should - * be fine and we don't need to do a usb_clear_halt(). - * - Jean II */ - pr_debug("%s(), Received -EPIPE, ignoring...\n", - __func__); - break; - default: - pr_debug("%s(), Unknown error %d\n", __func__, ret); - ret = -EIO; - goto err_out_3; - } - - /* Find our endpoints */ - interface = intf->cur_altsetting; - if(!irda_usb_parse_endpoints(self, interface->endpoint, - interface->desc.bNumEndpoints)) { - net_err_ratelimited("%s(), Bogus endpoints...\n", __func__); - ret = -EIO; - goto err_out_3; - } - - self->usbdev = dev; - - /* Find IrDA class descriptor */ - irda_desc = irda_usb_find_class_desc(intf); - ret = -ENODEV; - if (!irda_desc) - goto err_out_3; - - if (self->needspatch) { - ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), - 0x02, 0x40, 0, 0, NULL, 0, 500); - if (ret < 0) { - pr_debug("usb_control_msg failed %d\n", ret); - goto err_out_3; - } else { - mdelay(10); - } - } - - self->irda_desc = irda_desc; - self->present = 1; - self->netopen = 0; - self->usbintf = intf; - - /* Allocate the buffer for speed changes */ - /* Don't change this buffer size and allocation without doing - * some heavy and complete testing. Don't ask why :-( - * Jean II */ - ret = -ENOMEM; - self->speed_buff = kzalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL); - if (!self->speed_buff) - goto err_out_3; - - self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length, - GFP_KERNEL); - if (!self->tx_buff) - goto err_out_4; - - ret = irda_usb_open(self); - if (ret) - goto err_out_5; - - net_info_ratelimited("IrDA: Registered device %s\n", net->name); - usb_set_intfdata(intf, self); - - if (self->needspatch) { - /* Now we fetch and upload the firmware patch */ - ret = stir421x_patch_device(self); - self->needspatch = (ret < 0); - if (self->needspatch) { - net_err_ratelimited("STIR421X: Couldn't upload patch\n"); - goto err_out_6; - } - - /* replace IrDA class descriptor with what patched device is now reporting */ - irda_desc = irda_usb_find_class_desc (self->usbintf); - if (!irda_desc) { - ret = -ENODEV; - goto err_out_6; - } - kfree(self->irda_desc); - self->irda_desc = irda_desc; - irda_usb_init_qos(self); - } - - return 0; -err_out_6: - unregister_netdev(self->netdev); -err_out_5: - kfree(self->tx_buff); -err_out_4: - kfree(self->speed_buff); -err_out_3: - /* Free all urbs that we may have created */ - usb_free_urb(self->speed_urb); -err_out_2: - usb_free_urb(self->tx_urb); -err_out_1: - for (i = 0; i < self->max_rx_urb; i++) - usb_free_urb(self->rx_urb[i]); - kfree(self->rx_urb); -err_free_net: - free_netdev(net); -err_out: - return ret; -} - -/*------------------------------------------------------------------*/ -/* - * The current irda-usb device is removed, the USB layer tell us - * to shut it down... - * One of the constraints is that when we exit this function, - * we cannot use the usb_device no more. Gone. Destroyed. kfree(). - * Most other subsystem allow you to destroy the instance at a time - * when it's convenient to you, to postpone it to a later date, but - * not the USB subsystem. - * So, we must make bloody sure that everything gets deactivated. - * Jean II - */ -static void irda_usb_disconnect(struct usb_interface *intf) -{ - unsigned long flags; - struct irda_usb_cb *self = usb_get_intfdata(intf); - int i; - - usb_set_intfdata(intf, NULL); - if (!self) - return; - - /* Make sure that the Tx path is not executing. - Jean II */ - spin_lock_irqsave(&self->lock, flags); - - /* Oups ! We are not there any more. - * This will stop/desactivate the Tx path. - Jean II */ - self->present = 0; - - /* Kill defered Rx URB */ - del_timer(&self->rx_defer_timer); - - /* We need to have irq enabled to unlink the URBs. That's OK, - * at this point the Tx path is gone - Jean II */ - spin_unlock_irqrestore(&self->lock, flags); - - /* Hum... Check if networking is still active (avoid races) */ - if((self->netopen) || (self->irlap)) { - /* Accept no more transmissions */ - /*netif_device_detach(self->netdev);*/ - netif_stop_queue(self->netdev); - /* Stop all the receive URBs. Must be synchronous. */ - for (i = 0; i < self->max_rx_urb; i++) - usb_kill_urb(self->rx_urb[i]); - /* Cancel Tx and speed URB. - * Make sure it's synchronous to avoid races. */ - usb_kill_urb(self->tx_urb); - usb_kill_urb(self->speed_urb); - } - - /* Cleanup the device stuff */ - irda_usb_close(self); - /* No longer attached to USB bus */ - self->usbdev = NULL; - self->usbintf = NULL; - - /* Clean up our urbs */ - for (i = 0; i < self->max_rx_urb; i++) - usb_free_urb(self->rx_urb[i]); - kfree(self->rx_urb); - /* Clean up Tx and speed URB */ - usb_free_urb(self->tx_urb); - usb_free_urb(self->speed_urb); - - /* Free self and network device */ - free_netdev(self->netdev); - pr_debug("%s(), USB IrDA Disconnected\n", __func__); -} - -#ifdef CONFIG_PM -/* USB suspend, so power off the transmitter/receiver */ -static int irda_usb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct irda_usb_cb *self = usb_get_intfdata(intf); - int i; - - netif_device_detach(self->netdev); - - if (self->tx_urb != NULL) - usb_kill_urb(self->tx_urb); - if (self->speed_urb != NULL) - usb_kill_urb(self->speed_urb); - for (i = 0; i < self->max_rx_urb; i++) { - if (self->rx_urb[i] != NULL) - usb_kill_urb(self->rx_urb[i]); - } - return 0; -} - -/* Coming out of suspend, so reset hardware */ -static int irda_usb_resume(struct usb_interface *intf) -{ - struct irda_usb_cb *self = usb_get_intfdata(intf); - int i; - - for (i = 0; i < self->max_rx_urb; i++) { - if (self->rx_urb[i] != NULL) - usb_submit_urb(self->rx_urb[i], GFP_KERNEL); - } - - netif_device_attach(self->netdev); - return 0; -} -#endif - -/*------------------------------------------------------------------*/ -/* - * USB device callbacks - */ -static struct usb_driver irda_driver = { - .name = "irda-usb", - .probe = irda_usb_probe, - .disconnect = irda_usb_disconnect, - .id_table = dongles, -#ifdef CONFIG_PM - .suspend = irda_usb_suspend, - .resume = irda_usb_resume, -#endif -}; - -module_usb_driver(irda_driver); - -/* - * Module parameters - */ -module_param(qos_mtt_bits, int, 0); -MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); -MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>"); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/irda-usb.h b/drivers/staging/irda/drivers/irda-usb.h deleted file mode 100644 index 56ee8c16c5e2..000000000000 --- a/drivers/staging/irda/drivers/irda-usb.h +++ /dev/null @@ -1,175 +0,0 @@ -/***************************************************************************** - * - * Filename: irda-usb.h - * Version: 0.10 - * Description: IrDA-USB Driver - * Status: Experimental - * Author: Dag Brattli <dag@brattli.net> - * - * Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at> - * Copyright (C) 2000, Dag Brattli <dag@brattli.net> - * Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> - * Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com> - * Copyright (C) 2005, Milan Beno <beno@pobox.sk> - * Copyright (C) 2006, Nick FEdchik <nick@fedchik.org.ua> - * - * 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 <linux/ktime.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> /* struct irlap_cb */ - -#define RX_COPY_THRESHOLD 200 -#define IRDA_USB_MAX_MTU 2051 -#define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ - -/* Maximum number of active URB on the Rx path - * This is the amount of buffers the we keep between the USB harware and the - * IrDA stack. - * - * Note : the network layer does also queue the packets between us and the - * IrDA stack, and is actually pretty fast and efficient in doing that. - * Therefore, we don't need to have a large number of URBs, and we can - * perfectly live happy with only one. We certainly don't need to keep the - * full IrTTP window around here... - * I repeat for those who have trouble to understand : 1 URB is plenty - * good enough to handle back-to-back (brickwalled) frames. I tried it, - * it works (it's the hardware that has trouble doing it). - * - * Having 2 URBs would allow the USB stack to process one URB while we take - * care of the other and then swap the URBs... - * On the other hand, increasing the number of URB will have penalities - * in term of latency and will interact with the link management in IrLAP... - * Jean II */ -#define IU_MAX_ACTIVE_RX_URBS 1 /* Don't touch !!! */ - -/* When a Rx URB is passed back to us, we can't reuse it immediately, - * because it may still be referenced by the USB layer. Therefore we - * need to keep one extra URB in the Rx path. - * Jean II */ -#define IU_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + 1) - -/* Various ugly stuff to try to workaround generic problems */ -/* Send speed command in case of timeout, just for trying to get things sane */ -#define IU_BUG_KICK_TIMEOUT -/* Show the USB class descriptor */ -#undef IU_DUMP_CLASS_DESC -/* Assume a minimum round trip latency for USB transfer (in us)... - * USB transfer are done in the next USB slot if there is no traffic - * (1/19 msec) and is done at 12 Mb/s : - * Waiting for slot + tx = (53us + 16us) * 2 = 137us minimum. - * Rx notification will only be done at the end of the USB frame period : - * OHCI : frame period = 1ms - * UHCI : frame period = 1ms, but notification can take 2 or 3 ms :-( - * EHCI : frame period = 125us */ -#define IU_USB_MIN_RTT 500 /* This should be safe in most cases */ - -/* Inbound header */ -#define MEDIA_BUSY 0x80 - -#define SPEED_2400 0x01 -#define SPEED_9600 0x02 -#define SPEED_19200 0x03 -#define SPEED_38400 0x04 -#define SPEED_57600 0x05 -#define SPEED_115200 0x06 -#define SPEED_576000 0x07 -#define SPEED_1152000 0x08 -#define SPEED_4000000 0x09 -#define SPEED_16000000 0x0a - -/* Basic capabilities */ -#define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ -/* Main bugs */ -#define IUC_SPEED_BUG 0x01 /* Device doesn't set speed after the frame */ -#define IUC_NO_WINDOW 0x02 /* Device doesn't behave with big Rx window */ -#define IUC_NO_TURN 0x04 /* Device doesn't do turnaround by itself */ -/* Not currently used */ -#define IUC_SIR_ONLY 0x08 /* Device doesn't behave at FIR speeds */ -#define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ -#define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ -#define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ -#define IUC_STIR421X 0x80 /* SigmaTel 4210/4220/4116 VFIR */ - -/* USB class definitions */ -#define USB_IRDA_HEADER 0x01 -#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ -#define USB_DT_IRDA 0x21 -#define USB_IRDA_STIR421X_HEADER 0x03 -#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + \ - USB_IRDA_STIR421X_HEADER) - -struct irda_class_desc { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdSpecRevision; - __u8 bmDataSize; - __u8 bmWindowSize; - __u8 bmMinTurnaroundTime; - __le16 wBaudRate; - __u8 bmAdditionalBOFs; - __u8 bIrdaRateSniff; - __u8 bMaxUnicastList; -} __packed; - -/* class specific interface request to get the IrDA-USB class descriptor - * (6.2.5, USB-IrDA class spec 1.0) */ - -#define IU_REQ_GET_CLASS_DESC 0x06 -#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023 - -struct irda_usb_cb { - struct irda_class_desc *irda_desc; - struct usb_device *usbdev; /* init: probe_irda */ - struct usb_interface *usbintf; /* init: probe_irda */ - int netopen; /* Device is active for network */ - int present; /* Device is present on the bus */ - __u32 capability; /* Capability of the hardware */ - __u8 bulk_in_ep; /* Rx Endpoint assignments */ - __u8 bulk_out_ep; /* Tx Endpoint assignments */ - __u16 bulk_out_mtu; /* Max Tx packet size in bytes */ - __u8 bulk_int_ep; /* Interrupt Endpoint assignments */ - - __u8 max_rx_urb; - struct urb **rx_urb; /* URBs used to receive data frames */ - struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */ - struct urb *tx_urb; /* URB used to send data frames */ - struct urb *speed_urb; /* URB used to send speed commands */ - - struct net_device *netdev; /* Yes! we are some kind of netdev. */ - struct irlap_cb *irlap; /* The link layer we are binded to */ - struct qos_info qos; - char *speed_buff; /* Buffer for speed changes */ - char *tx_buff; - - ktime_t stamp; - - spinlock_t lock; /* For serializing Tx operations */ - - __u16 xbofs; /* Current xbofs setting */ - __s16 new_xbofs; /* xbofs we need to set */ - __u32 speed; /* Current speed */ - __s32 new_speed; /* speed we need to set */ - - __u8 header_length; /* USB-IrDA frame header size */ - int needspatch; /* device needs firmware patch */ - - struct timer_list rx_defer_timer; /* Wait for Rx error to clear */ - struct urb *rx_defer_timer_urb; /* URB attached to rx_defer_timer */ -}; - diff --git a/drivers/staging/irda/drivers/irtty-sir.c b/drivers/staging/irda/drivers/irtty-sir.c deleted file mode 100644 index 7a20a9a4663a..000000000000 --- a/drivers/staging/irda/drivers/irtty-sir.c +++ /dev/null @@ -1,570 +0,0 @@ -/********************************************************************* - * - * Filename: irtty-sir.c - * Version: 2.0 - * Description: IrDA line discipline implementation - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Sun Oct 27 22:13:30 2002 - * Modified by: Martin Diehl <mad@mdiehl.de> - * Sources: slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> - * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> - * - * Copyright (c) 1998-2000 Dag Brattli, - * Copyright (c) 2002 Martin Diehl, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/init.h> -#include <linux/uaccess.h> -#include <linux/delay.h> -#include <linux/mutex.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#include "sir-dev.h" -#include "irtty-sir.h" - -static int qos_mtt_bits = 0x03; /* 5 ms or more */ - -module_param(qos_mtt_bits, int, 0); -MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); - -/* ------------------------------------------------------- */ - -/* device configuration callbacks always invoked with irda-thread context */ - -/* find out, how many chars we have in buffers below us - * this is allowed to lie, i.e. return less chars than we - * actually have. The returned value is used to determine - * how long the irdathread should wait before doing the - * real blocking wait_until_sent() - */ - -static int irtty_chars_in_buffer(struct sir_dev *dev) -{ - struct sirtty_cb *priv = dev->priv; - - IRDA_ASSERT(priv != NULL, return -1;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); - - return tty_chars_in_buffer(priv->tty); -} - -/* Wait (sleep) until underlaying hardware finished transmission - * i.e. hardware buffers are drained - * this must block and not return before all characters are really sent - * - * If the tty sits on top of a 16550A-like uart, there are typically - * up to 16 bytes in the fifo - f.e. 9600 bps 8N1 needs 16.7 msec - * - * With usbserial the uart-fifo is basically replaced by the converter's - * outgoing endpoint buffer, which can usually hold 64 bytes (at least). - * With pl2303 it appears we are safe with 60msec here. - * - * I really wish all serial drivers would provide - * correct implementation of wait_until_sent() - */ - -#define USBSERIAL_TX_DONE_DELAY 60 - -static void irtty_wait_until_sent(struct sir_dev *dev) -{ - struct sirtty_cb *priv = dev->priv; - struct tty_struct *tty; - - IRDA_ASSERT(priv != NULL, return;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); - - tty = priv->tty; - if (tty->ops->wait_until_sent) { - tty->ops->wait_until_sent(tty, msecs_to_jiffies(100)); - } - else { - msleep(USBSERIAL_TX_DONE_DELAY); - } -} - -/* - * Function irtty_change_speed (dev, speed) - * - * Change the speed of the serial port. - * - * This may sleep in set_termios (usbserial driver f.e.) and must - * not be called from interrupt/timer/tasklet therefore. - * All such invocations are deferred to kIrDAd now so we can sleep there. - */ - -static int irtty_change_speed(struct sir_dev *dev, unsigned speed) -{ - struct sirtty_cb *priv = dev->priv; - struct tty_struct *tty; - struct ktermios old_termios; - int cflag; - - IRDA_ASSERT(priv != NULL, return -1;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); - - tty = priv->tty; - - down_write(&tty->termios_rwsem); - old_termios = tty->termios; - cflag = tty->termios.c_cflag; - tty_encode_baud_rate(tty, speed, speed); - if (tty->ops->set_termios) - tty->ops->set_termios(tty, &old_termios); - priv->io.speed = speed; - up_write(&tty->termios_rwsem); - - return 0; -} - -/* - * Function irtty_set_dtr_rts (dev, dtr, rts) - * - * This function can be used by dongles etc. to set or reset the status - * of the dtr and rts lines - */ - -static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) -{ - struct sirtty_cb *priv = dev->priv; - int set = 0; - int clear = 0; - - IRDA_ASSERT(priv != NULL, return -1;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); - - if (rts) - set |= TIOCM_RTS; - else - clear |= TIOCM_RTS; - if (dtr) - set |= TIOCM_DTR; - else - clear |= TIOCM_DTR; - - /* - * We can't use ioctl() because it expects a non-null file structure, - * and we don't have that here. - * This function is not yet defined for all tty driver, so - * let's be careful... Jean II - */ - IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;); - priv->tty->ops->tiocmset(priv->tty, set, clear); - - return 0; -} - -/* ------------------------------------------------------- */ - -/* called from sir_dev when there is more data to send - * context is either netdev->hard_xmit or some transmit-completion bh - * i.e. we are under spinlock here and must not sleep. - */ - -static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t len) -{ - struct sirtty_cb *priv = dev->priv; - struct tty_struct *tty; - int writelen; - - IRDA_ASSERT(priv != NULL, return -1;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); - - tty = priv->tty; - if (!tty->ops->write) - return 0; - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - writelen = tty_write_room(tty); - if (writelen > len) - writelen = len; - return tty->ops->write(tty, ptr, writelen); -} - -/* ------------------------------------------------------- */ - -/* irda line discipline callbacks */ - -/* - * Function irtty_receive_buf( tty, cp, count) - * - * Handle the 'receiver data ready' interrupt. This function is called - * by the 'tty_io' module in the kernel when a block of IrDA data has - * been received, which can now be decapsulated and delivered for - * further processing - * - * calling context depends on underlying driver and tty->port->low_latency! - * for example (low_latency: 1 / 0): - * serial.c: uart-interrupt / softint - * usbserial: urb-complete-interrupt / softint - */ - -static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct sir_dev *dev; - struct sirtty_cb *priv = tty->disc_data; - int i; - - IRDA_ASSERT(priv != NULL, return;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); - - if (unlikely(count==0)) /* yes, this happens */ - return; - - dev = priv->dev; - if (!dev) { - net_warn_ratelimited("%s(), not ready yet!\n", __func__); - return; - } - - for (i = 0; i < count; i++) { - /* - * Characters received with a parity error, etc? - */ - if (fp && *fp++) { - pr_debug("Framing or parity error!\n"); - sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */ - return; - } - } - - sirdev_receive(dev, cp, count); -} - -/* - * Function irtty_write_wakeup (tty) - * - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - * - */ -static void irtty_write_wakeup(struct tty_struct *tty) -{ - struct sirtty_cb *priv = tty->disc_data; - - IRDA_ASSERT(priv != NULL, return;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); - - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - if (priv->dev) - sirdev_write_complete(priv->dev); -} - -/* ------------------------------------------------------- */ - -/* - * Function irtty_stop_receiver (tty, stop) - * - */ - -static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) -{ - struct ktermios old_termios; - int cflag; - - down_write(&tty->termios_rwsem); - old_termios = tty->termios; - cflag = tty->termios.c_cflag; - - if (stop) - cflag &= ~CREAD; - else - cflag |= CREAD; - - tty->termios.c_cflag = cflag; - if (tty->ops->set_termios) - tty->ops->set_termios(tty, &old_termios); - up_write(&tty->termios_rwsem); -} - -/*****************************************************************/ - -/* serialize ldisc open/close with sir_dev */ -static DEFINE_MUTEX(irtty_mutex); - -/* notifier from sir_dev when irda% device gets opened (ifup) */ - -static int irtty_start_dev(struct sir_dev *dev) -{ - struct sirtty_cb *priv; - struct tty_struct *tty; - - /* serialize with ldisc open/close */ - mutex_lock(&irtty_mutex); - - priv = dev->priv; - if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) { - mutex_unlock(&irtty_mutex); - return -ESTALE; - } - - tty = priv->tty; - - if (tty->ops->start) - tty->ops->start(tty); - /* Make sure we can receive more data */ - irtty_stop_receiver(tty, FALSE); - - mutex_unlock(&irtty_mutex); - return 0; -} - -/* notifier from sir_dev when irda% device gets closed (ifdown) */ - -static int irtty_stop_dev(struct sir_dev *dev) -{ - struct sirtty_cb *priv; - struct tty_struct *tty; - - /* serialize with ldisc open/close */ - mutex_lock(&irtty_mutex); - - priv = dev->priv; - if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) { - mutex_unlock(&irtty_mutex); - return -ESTALE; - } - - tty = priv->tty; - - /* Make sure we don't receive more data */ - irtty_stop_receiver(tty, TRUE); - if (tty->ops->stop) - tty->ops->stop(tty); - - mutex_unlock(&irtty_mutex); - - return 0; -} - -/* ------------------------------------------------------- */ - -static struct sir_driver sir_tty_drv = { - .owner = THIS_MODULE, - .driver_name = "sir_tty", - .start_dev = irtty_start_dev, - .stop_dev = irtty_stop_dev, - .do_write = irtty_do_write, - .chars_in_buffer = irtty_chars_in_buffer, - .wait_until_sent = irtty_wait_until_sent, - .set_speed = irtty_change_speed, - .set_dtr_rts = irtty_set_dtr_rts, -}; - -/* ------------------------------------------------------- */ - -/* - * Function irtty_ioctl (tty, file, cmd, arg) - * - * The Swiss army knife of system calls :-) - * - */ -static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct irtty_info { char name[6]; } info; - struct sir_dev *dev; - struct sirtty_cb *priv = tty->disc_data; - int err = 0; - - IRDA_ASSERT(priv != NULL, return -ENODEV;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;); - - pr_debug("%s(cmd=0x%X)\n", __func__, cmd); - - dev = priv->dev; - IRDA_ASSERT(dev != NULL, return -1;); - - switch (cmd) { - case IRTTY_IOCTDONGLE: - /* this call blocks for completion */ - err = sirdev_set_dongle(dev, (IRDA_DONGLE) arg); - break; - - case IRTTY_IOCGET: - IRDA_ASSERT(dev->netdev != NULL, return -1;); - - memset(&info, 0, sizeof(info)); - strncpy(info.name, dev->netdev->name, sizeof(info.name)-1); - - if (copy_to_user((void __user *)arg, &info, sizeof(info))) - err = -EFAULT; - break; - default: - err = tty_mode_ioctl(tty, file, cmd, arg); - break; - } - return err; -} - - -/* - * Function irtty_open(tty) - * - * This function is called by the TTY module when the IrDA line - * discipline is called for. Because we are sure the tty line exists, - * we only have to link it to a free IrDA channel. - */ -static int irtty_open(struct tty_struct *tty) -{ - struct sir_dev *dev; - struct sirtty_cb *priv; - int ret = 0; - - /* Module stuff handled via irda_ldisc.owner - Jean II */ - - /* stop the underlying driver */ - irtty_stop_receiver(tty, TRUE); - if (tty->ops->stop) - tty->ops->stop(tty); - - tty_driver_flush_buffer(tty); - - /* apply mtt override */ - sir_tty_drv.qos_mtt_bits = qos_mtt_bits; - - /* get a sir device instance for this driver */ - dev = sirdev_get_instance(&sir_tty_drv, tty->name); - if (!dev) { - ret = -ENODEV; - goto out; - } - - /* allocate private device info block */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto out_put; - } - - priv->magic = IRTTY_MAGIC; - priv->tty = tty; - priv->dev = dev; - - /* serialize with start_dev - in case we were racing with ifup */ - mutex_lock(&irtty_mutex); - - dev->priv = priv; - tty->disc_data = priv; - tty->receive_room = 65536; - - mutex_unlock(&irtty_mutex); - - pr_debug("%s - %s: irda line discipline opened\n", __func__, tty->name); - - return 0; - -out_put: - sirdev_put_instance(dev); -out: - return ret; -} - -/* - * Function irtty_close (tty) - * - * Close down a IrDA channel. This means flushing out any pending queues, - * and then restoring the TTY line discipline to what it was before it got - * hooked to IrDA (which usually is TTY again). - */ -static void irtty_close(struct tty_struct *tty) -{ - struct sirtty_cb *priv = tty->disc_data; - - IRDA_ASSERT(priv != NULL, return;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); - - /* Hm, with a dongle attached the dongle driver wants - * to close the dongle - which requires the use of - * some tty write and/or termios or ioctl operations. - * Are we allowed to call those when already requested - * to shutdown the ldisc? - * If not, we should somehow mark the dev being staled. - * Question remains, how to close the dongle in this case... - * For now let's assume we are granted to issue tty driver calls - * until we return here from the ldisc close. I'm just wondering - * how this behaves with hotpluggable serial hardware like - * rs232-pcmcia card or usb-serial... - * - * priv->tty = NULL?; - */ - - /* we are dead now */ - tty->disc_data = NULL; - - sirdev_put_instance(priv->dev); - - /* Stop tty */ - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - if (tty->ops->stop) - tty->ops->stop(tty); - - kfree(priv); - - pr_debug("%s - %s: irda line discipline closed\n", __func__, tty->name); -} - -/* ------------------------------------------------------- */ - -static struct tty_ldisc_ops irda_ldisc = { - .magic = TTY_LDISC_MAGIC, - .name = "irda", - .flags = 0, - .open = irtty_open, - .close = irtty_close, - .read = NULL, - .write = NULL, - .ioctl = irtty_ioctl, - .poll = NULL, - .receive_buf = irtty_receive_buf, - .write_wakeup = irtty_write_wakeup, - .owner = THIS_MODULE, -}; - -/* ------------------------------------------------------- */ - -static int __init irtty_sir_init(void) -{ - int err; - - if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) - net_err_ratelimited("IrDA: can't register line discipline (err = %d)\n", - err); - return err; -} - -static void __exit irtty_sir_cleanup(void) -{ - int err; - - if ((err = tty_unregister_ldisc(N_IRDA))) { - net_err_ratelimited("%s(), can't unregister line discipline (err = %d)\n", - __func__, err); - } -} - -module_init(irtty_sir_init); -module_exit(irtty_sir_cleanup); - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("IrDA TTY device driver"); -MODULE_ALIAS_LDISC(N_IRDA); -MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/irda/drivers/irtty-sir.h b/drivers/staging/irda/drivers/irtty-sir.h deleted file mode 100644 index b132d8f6eb13..000000000000 --- a/drivers/staging/irda/drivers/irtty-sir.h +++ /dev/null @@ -1,34 +0,0 @@ -/********************************************************************* - * - * sir_tty.h: definitions for the irtty_sir client driver (former irtty) - * - * Copyright (c) 2002 Martin Diehl - * - * 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. - * - ********************************************************************/ - -#ifndef IRTTYSIR_H -#define IRTTYSIR_H - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> // chipio_t - -#define IRTTY_IOC_MAGIC 'e' -#define IRTTY_IOCTDONGLE _IO(IRTTY_IOC_MAGIC, 1) -#define IRTTY_IOCGET _IOR(IRTTY_IOC_MAGIC, 2, struct irtty_info) -#define IRTTY_IOC_MAXNR 2 - -struct sirtty_cb { - magic_t magic; - - struct sir_dev *dev; - struct tty_struct *tty; - - chipio_t io; /* IrDA controller information */ -}; - -#endif diff --git a/drivers/staging/irda/drivers/kingsun-sir.c b/drivers/staging/irda/drivers/kingsun-sir.c deleted file mode 100644 index 4fd4ac2fe09f..000000000000 --- a/drivers/staging/irda/drivers/kingsun-sir.c +++ /dev/null @@ -1,634 +0,0 @@ -/***************************************************************************** -* -* Filename: kingsun-sir.c -* Version: 0.1.1 -* Description: Irda KingSun/DonShine USB Dongle -* Status: Experimental -* Author: Alex VillacÃs Lasso <a_villacis@palosanto.com> -* -* Based on stir4200 and mcs7780 drivers, with (strange?) differences -* -* 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. -* -* 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. -* -*****************************************************************************/ - -/* - * This is my current (2007-04-25) understanding of how this dongle is supposed - * to work. This is based on reverse-engineering and examination of the packet - * data sent and received by the WinXP driver using USBSnoopy. Feel free to - * update here as more of this dongle is known: - * - * General: Unlike the other USB IrDA dongles, this particular dongle exposes, - * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle, - * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in - * order to receive data. - * Transmission: Just like stir4200, this dongle uses a raw stream of data, - * which needs to be wrapped and escaped in a similar way as in stir4200.c. - * Reception: Poll-based, as in stir4200. Each read returns the contents of a - * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes - * (1-7) of valid data contained within the remaining 7 bytes. For example, if - * the buffer had the following contents: - * 06 ff ff ff c0 01 04 aa - * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the - * end is garbage (left over from a previous reception) and is discarded. - * If a read returns an "impossible" value as the length of valid data (such as - * 0x36) in the first byte, then the buffer is uninitialized (as is the case of - * first plug-in) and its contents should be discarded. There is currently no - * evidence that the top 5 bits of the 1st byte of the buffer can have values - * other than 0 once reception begins. - * Once valid bytes are collected, the assembled stream is a sequence of - * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c. - * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after - * a successful read from the host, which means that in absence of further - * reception, repeated reads from the dongle will return the exact same - * contents repeatedly. Attempts to be smart and cache a previous read seem - * to result in corrupted packets, so this driver depends on the unwrap logic - * to sort out any repeated reads. - * Speed change: no commands observed so far to change speed, assumed fixed - * 9600bps (SIR). - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/device.h> -#include <linux/crc32.h> - -#include <asm/unaligned.h> -#include <asm/byteorder.h> -#include <linux/uaccess.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/crc.h> - -/* - * According to lsusb, 0x07c0 is assigned to - * "Code Mercenaries Hard- und Software GmbH" - */ -#define KING_VENDOR_ID 0x07c0 -#define KING_PRODUCT_ID 0x4200 - -/* These are the currently known USB ids */ -static const struct usb_device_id dongles[] = { - /* KingSun Co,Ltd IrDA/USB Bridge */ - { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, dongles); - -#define KINGSUN_MTT 0x07 - -#define KINGSUN_FIFO_SIZE 4096 -#define KINGSUN_EP_IN 0 -#define KINGSUN_EP_OUT 1 - -struct kingsun_cb { - struct usb_device *usbdev; /* init: probe_irda */ - struct net_device *netdev; /* network layer */ - struct irlap_cb *irlap; /* The link layer we are binded to */ - - struct qos_info qos; - - __u8 *in_buf; /* receive buffer */ - __u8 *out_buf; /* transmit buffer */ - __u8 max_rx; /* max. atomic read from dongle - (usually 8), also size of in_buf */ - __u8 max_tx; /* max. atomic write to dongle - (usually 8) */ - - iobuff_t rx_buff; /* receive unwrap state machine */ - spinlock_t lock; - int receiving; - - __u8 ep_in; - __u8 ep_out; - - struct urb *tx_urb; - struct urb *rx_urb; -}; - -/* Callback transmission routine */ -static void kingsun_send_irq(struct urb *urb) -{ - struct kingsun_cb *kingsun = urb->context; - struct net_device *netdev = kingsun->netdev; - - /* in process of stopping, just drop data */ - if (!netif_running(kingsun->netdev)) { - dev_err(&kingsun->usbdev->dev, - "kingsun_send_irq: Network not running!\n"); - return; - } - - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - dev_err(&kingsun->usbdev->dev, - "kingsun_send_irq: urb asynchronously failed - %d\n", - urb->status); - } - netif_wake_queue(netdev); -} - -/* - * Called from net/core when new frame is available. - */ -static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct kingsun_cb *kingsun; - int wraplen; - int ret = 0; - - netif_stop_queue(netdev); - - /* the IRDA wrapping routines don't deal with non linear skb */ - SKB_LINEAR_ASSERT(skb); - - kingsun = netdev_priv(netdev); - - spin_lock(&kingsun->lock); - - /* Append data to the end of whatever data remains to be transmitted */ - wraplen = async_wrap_skb(skb, - kingsun->out_buf, - KINGSUN_FIFO_SIZE); - - /* Calculate how much data can be transmitted in this urb */ - usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev, - usb_sndintpipe(kingsun->usbdev, kingsun->ep_out), - kingsun->out_buf, wraplen, kingsun_send_irq, - kingsun, 1); - - if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) { - dev_err(&kingsun->usbdev->dev, - "kingsun_hard_xmit: failed tx_urb submit: %d\n", ret); - switch (ret) { - case -ENODEV: - case -EPIPE: - break; - default: - netdev->stats.tx_errors++; - netif_start_queue(netdev); - } - } else { - netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; - } - - dev_kfree_skb(skb); - spin_unlock(&kingsun->lock); - - return NETDEV_TX_OK; -} - -/* Receive callback function */ -static void kingsun_rcv_irq(struct urb *urb) -{ - struct kingsun_cb *kingsun = urb->context; - int ret; - - /* in process of stopping, just drop data */ - if (!netif_running(kingsun->netdev)) { - kingsun->receiving = 0; - return; - } - - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - dev_err(&kingsun->usbdev->dev, - "kingsun_rcv_irq: urb asynchronously failed - %d\n", - urb->status); - kingsun->receiving = 0; - return; - } - - if (urb->actual_length == kingsun->max_rx) { - __u8 *bytes = urb->transfer_buffer; - int i; - - /* The very first byte in the buffer indicates the length of - valid data in the read. This byte must be in the range - 1..kingsun->max_rx -1 . Values outside this range indicate - an uninitialized Rx buffer when the dongle has just been - plugged in. */ - if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) { - for (i = 1; i <= bytes[0]; i++) { - async_unwrap_char(kingsun->netdev, - &kingsun->netdev->stats, - &kingsun->rx_buff, bytes[i]); - } - kingsun->receiving = - (kingsun->rx_buff.state != OUTSIDE_FRAME) - ? 1 : 0; - } - } else if (urb->actual_length > 0) { - dev_err(&kingsun->usbdev->dev, - "%s(): Unexpected response length, expected %d got %d\n", - __func__, kingsun->max_rx, urb->actual_length); - } - /* This urb has already been filled in kingsun_net_open */ - ret = usb_submit_urb(urb, GFP_ATOMIC); -} - -/* - * Function kingsun_net_open (dev) - * - * Network device is taken up. Usually this is done by "ifconfig irda0 up" - */ -static int kingsun_net_open(struct net_device *netdev) -{ - struct kingsun_cb *kingsun = netdev_priv(netdev); - int err = -ENOMEM; - char hwname[16]; - - /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */ - kingsun->receiving = 0; - - /* Initialize for SIR to copy data directly into skb. */ - kingsun->rx_buff.in_frame = FALSE; - kingsun->rx_buff.state = OUTSIDE_FRAME; - kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU; - kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (!kingsun->rx_buff.skb) - goto free_mem; - - skb_reserve(kingsun->rx_buff.skb, 1); - kingsun->rx_buff.head = kingsun->rx_buff.skb->data; - - kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->rx_urb) - goto free_mem; - - kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->tx_urb) - goto free_mem; - - /* - * Now that everything should be initialized properly, - * Open new IrLAP layer instance to take care of us... - */ - sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); - kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); - if (!kingsun->irlap) { - dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); - goto free_mem; - } - - /* Start first reception */ - usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, - usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), - kingsun->in_buf, kingsun->max_rx, - kingsun_rcv_irq, kingsun, 1); - kingsun->rx_urb->status = 0; - err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); - if (err) { - dev_err(&kingsun->usbdev->dev, - "first urb-submit failed: %d\n", err); - goto close_irlap; - } - - netif_start_queue(netdev); - - /* Situation at this point: - - all work buffers allocated - - urbs allocated and ready to fill - - max rx packet known (in max_rx) - - unwrap state machine initialized, in state outside of any frame - - receive request in progress - - IrLAP layer started, about to hand over packets to send - */ - - return 0; - - close_irlap: - irlap_close(kingsun->irlap); - free_mem: - if (kingsun->tx_urb) { - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - } - if (kingsun->rx_urb) { - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - } - if (kingsun->rx_buff.skb) { - kfree_skb(kingsun->rx_buff.skb); - kingsun->rx_buff.skb = NULL; - kingsun->rx_buff.head = NULL; - } - return err; -} - -/* - * Function kingsun_net_close (kingsun) - * - * Network device is taken down. Usually this is done by - * "ifconfig irda0 down" - */ -static int kingsun_net_close(struct net_device *netdev) -{ - struct kingsun_cb *kingsun = netdev_priv(netdev); - - /* Stop transmit processing */ - netif_stop_queue(netdev); - - /* Mop up receive && transmit urb's */ - usb_kill_urb(kingsun->tx_urb); - usb_kill_urb(kingsun->rx_urb); - - usb_free_urb(kingsun->tx_urb); - usb_free_urb(kingsun->rx_urb); - - kingsun->tx_urb = NULL; - kingsun->rx_urb = NULL; - - kfree_skb(kingsun->rx_buff.skb); - kingsun->rx_buff.skb = NULL; - kingsun->rx_buff.head = NULL; - kingsun->rx_buff.in_frame = FALSE; - kingsun->rx_buff.state = OUTSIDE_FRAME; - kingsun->receiving = 0; - - /* Stop and remove instance of IrLAP */ - if (kingsun->irlap) - irlap_close(kingsun->irlap); - - kingsun->irlap = NULL; - - return 0; -} - -/* - * IOCTLs : Extra out-of-band network commands... - */ -static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, - int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct kingsun_cb *kingsun = netdev_priv(netdev); - int ret = 0; - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the device is still there */ - if (netif_device_present(kingsun->netdev)) - /* No observed commands for speed change */ - ret = -EOPNOTSUPP; - break; - - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the IrDA stack is still there */ - if (netif_running(kingsun->netdev)) - irda_device_set_media_busy(kingsun->netdev, TRUE); - break; - - case SIOCGRECEIVING: - /* Only approximately true */ - irq->ifr_receiving = kingsun->receiving; - break; - - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -static const struct net_device_ops kingsun_ops = { - .ndo_start_xmit = kingsun_hard_xmit, - .ndo_open = kingsun_net_open, - .ndo_stop = kingsun_net_close, - .ndo_do_ioctl = kingsun_net_ioctl, -}; - -/* - * This routine is called by the USB subsystem for each new device - * in the system. We need to check if the device is ours, and in - * this case start handling it. - */ -static int kingsun_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_host_interface *interface; - struct usb_endpoint_descriptor *endpoint; - - struct usb_device *dev = interface_to_usbdev(intf); - struct kingsun_cb *kingsun = NULL; - struct net_device *net = NULL; - int ret = -ENOMEM; - int pipe, maxp_in, maxp_out; - __u8 ep_in; - __u8 ep_out; - - /* Check that there really are two interrupt endpoints. - Check based on the one in drivers/usb/input/usbmouse.c - */ - interface = intf->cur_altsetting; - if (interface->desc.bNumEndpoints != 2) { - dev_err(&intf->dev, - "kingsun-sir: expected 2 endpoints, found %d\n", - interface->desc.bNumEndpoints); - return -ENODEV; - } - endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; - if (!usb_endpoint_is_int_in(endpoint)) { - dev_err(&intf->dev, - "kingsun-sir: endpoint 0 is not interrupt IN\n"); - return -ENODEV; - } - - ep_in = endpoint->bEndpointAddress; - pipe = usb_rcvintpipe(dev, ep_in); - maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - if (maxp_in > 255 || maxp_in <= 1) { - dev_err(&intf->dev, - "endpoint 0 has max packet size %d not in range\n", - maxp_in); - return -ENODEV; - } - - endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; - if (!usb_endpoint_is_int_out(endpoint)) { - dev_err(&intf->dev, - "kingsun-sir: endpoint 1 is not interrupt OUT\n"); - return -ENODEV; - } - - ep_out = endpoint->bEndpointAddress; - pipe = usb_sndintpipe(dev, ep_out); - maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - /* Allocate network device container. */ - net = alloc_irdadev(sizeof(*kingsun)); - if(!net) - goto err_out1; - - SET_NETDEV_DEV(net, &intf->dev); - kingsun = netdev_priv(net); - kingsun->irlap = NULL; - kingsun->tx_urb = NULL; - kingsun->rx_urb = NULL; - kingsun->ep_in = ep_in; - kingsun->ep_out = ep_out; - kingsun->in_buf = NULL; - kingsun->out_buf = NULL; - kingsun->max_rx = (__u8)maxp_in; - kingsun->max_tx = (__u8)maxp_out; - kingsun->netdev = net; - kingsun->usbdev = dev; - kingsun->rx_buff.in_frame = FALSE; - kingsun->rx_buff.state = OUTSIDE_FRAME; - kingsun->rx_buff.skb = NULL; - kingsun->receiving = 0; - spin_lock_init(&kingsun->lock); - - /* Allocate input buffer */ - kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL); - if (!kingsun->in_buf) - goto free_mem; - - /* Allocate output buffer */ - kingsun->out_buf = kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL); - if (!kingsun->out_buf) - goto free_mem; - - printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, " - "Vendor: %x, Product: %x\n", - dev->devnum, le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&kingsun->qos); - - /* That's the Rx capability. */ - kingsun->qos.baud_rate.bits &= IR_9600; - kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; - irda_qos_bits_to_value(&kingsun->qos); - - /* Override the network functions we need to use */ - net->netdev_ops = &kingsun_ops; - - ret = register_netdev(net); - if (ret != 0) - goto free_mem; - - dev_info(&net->dev, "IrDA: Registered KingSun/DonShine device %s\n", - net->name); - - usb_set_intfdata(intf, kingsun); - - /* Situation at this point: - - all work buffers allocated - - urbs not allocated, set to NULL - - max rx packet known (in max_rx) - - unwrap state machine (partially) initialized, but skb == NULL - */ - - return 0; - -free_mem: - kfree(kingsun->out_buf); - kfree(kingsun->in_buf); - free_netdev(net); -err_out1: - return ret; -} - -/* - * The current device is removed, the USB layer tell us to shut it down... - */ -static void kingsun_disconnect(struct usb_interface *intf) -{ - struct kingsun_cb *kingsun = usb_get_intfdata(intf); - - if (!kingsun) - return; - - unregister_netdev(kingsun->netdev); - - /* Mop up receive && transmit urb's */ - if (kingsun->tx_urb != NULL) { - usb_kill_urb(kingsun->tx_urb); - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - } - if (kingsun->rx_urb != NULL) { - usb_kill_urb(kingsun->rx_urb); - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - } - - kfree(kingsun->out_buf); - kfree(kingsun->in_buf); - free_netdev(kingsun->netdev); - - usb_set_intfdata(intf, NULL); -} - -#ifdef CONFIG_PM -/* USB suspend, so power off the transmitter/receiver */ -static int kingsun_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct kingsun_cb *kingsun = usb_get_intfdata(intf); - - netif_device_detach(kingsun->netdev); - if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb); - if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb); - return 0; -} - -/* Coming out of suspend, so reset hardware */ -static int kingsun_resume(struct usb_interface *intf) -{ - struct kingsun_cb *kingsun = usb_get_intfdata(intf); - - if (kingsun->rx_urb != NULL) - usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); - netif_device_attach(kingsun->netdev); - - return 0; -} -#endif - -/* - * USB device callbacks - */ -static struct usb_driver irda_driver = { - .name = "kingsun-sir", - .probe = kingsun_probe, - .disconnect = kingsun_disconnect, - .id_table = dongles, -#ifdef CONFIG_PM - .suspend = kingsun_suspend, - .resume = kingsun_resume, -#endif -}; - -module_usb_driver(irda_driver); - -MODULE_AUTHOR("Alex VillacÃs Lasso <a_villacis@palosanto.com>"); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/ks959-sir.c b/drivers/staging/irda/drivers/ks959-sir.c deleted file mode 100644 index 8025741e7586..000000000000 --- a/drivers/staging/irda/drivers/ks959-sir.c +++ /dev/null @@ -1,912 +0,0 @@ -/***************************************************************************** -* -* Filename: ks959-sir.c -* Version: 0.1.2 -* Description: Irda KingSun KS-959 USB Dongle -* Status: Experimental -* Author: Alex VillacÃs Lasso <a_villacis@palosanto.com> -* with help from Domen Puncer <domen@coderock.org> -* -* Based on stir4200, mcs7780, kingsun-sir drivers. -* -* 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. -* -* 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. -* -*****************************************************************************/ - -/* - * Following is my most current (2007-07-17) understanding of how the Kingsun - * KS-959 dongle is supposed to work. This information was deduced by - * reverse-engineering and examining the USB traffic captured with USBSnoopy - * from the WinXP driver. Feel free to update here as more of the dongle is - * known. - * - * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for - * invaluable help in cracking the obfuscation and padding required for this - * dongle. - * - * General: This dongle exposes one interface with one interrupt IN endpoint. - * However, the interrupt endpoint is NOT used at all for this dongle. Instead, - * this dongle uses control transfers for everything, including sending and - * receiving the IrDA frame data. Apparently the interrupt endpoint is just a - * dummy to ensure the dongle has a valid interface to present to the PC.And I - * thought the DonShine dongle was weird... In addition, this dongle uses - * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent - * and received, from the dongle. I call it obfuscation because the XOR keying - * and padding required to produce an USB traffic acceptable for the dongle can - * not be explained by any other technical requirement. - * - * Transmission: To transmit an IrDA frame, the driver must prepare a control - * URB with the following as a setup packet: - * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE - * bRequest 0x09 - * wValue <length of valid data before padding, little endian> - * wIndex 0x0000 - * wLength <length of padded data> - * The payload packet must be manually wrapped and escaped (as in stir4200.c), - * then padded and obfuscated before being sent. Both padding and obfuscation - * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the - * designer/programmer of the dongle used his name as a source for the - * obfuscation. WTF?! - * Apparently the dongle cannot handle payloads larger than 256 bytes. The - * driver has to perform fragmentation in order to send anything larger than - * this limit. - * - * Reception: To receive data, the driver must poll the dongle regularly (like - * kingsun-sir.c) with control URBs and the following as a setup packet: - * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE - * bRequest 0x01 - * wValue 0x0200 - * wIndex 0x0000 - * wLength 0x0800 (size of available buffer) - * If there is data to be read, it will be returned as the response payload. - * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate - * it, the driver must XOR every byte, in sequence, with a value that starts at - * 1 and is incremented with each byte processed, and then with 0x55. The value - * incremented with each byte processed overflows as an unsigned char. The - * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped - * as in stir4200.c The incremented value is NOT reset with each frame, but is - * kept across the entire session with the dongle. Also, the dongle inserts an - * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which - * must be skipped. - * - * Speed change: To change the speed of the dongle, the driver prepares a - * control URB with the following as a setup packet: - * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE - * bRequest 0x09 - * wValue 0x0200 - * wIndex 0x0001 - * wLength 0x0008 (length of the payload) - * The payload is a 8-byte record, apparently identical to the one used in - * drivers/usb/serial/cypress_m8.c to change speed: - * __u32 baudSpeed; - * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits - * unsigned int : 1; - * unsigned int stopBits : 1; - * unsigned int parityEnable : 1; - * unsigned int parityType : 1; - * unsigned int : 1; - * unsigned int reset : 1; - * unsigned char reserved[3]; // set to 0 - * - * For now only SIR speeds have been observed with this dongle. Therefore, - * nothing is known on what changes (if any) must be done to frame wrapping / - * unwrapping for higher than SIR speeds. This driver assumes no change is - * necessary and announces support for all the way to 57600 bps. Although the - * package announces support for up to 4MBps, tests with a Sony Ericcson K300 - * phone show corruption when receiving large frames at 115200 bps, the highest - * speed announced by the phone. However, transmission at 115200 bps is OK. Go - * figure. Since I don't know whether the phone or the dongle is at fault, max - * announced speed is 57600 bps until someone produces a device that can run - * at higher speeds with this dongle. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/device.h> -#include <linux/crc32.h> - -#include <asm/unaligned.h> -#include <asm/byteorder.h> -#include <linux/uaccess.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/crc.h> - -#define KS959_VENDOR_ID 0x07d0 -#define KS959_PRODUCT_ID 0x4959 - -/* These are the currently known USB ids */ -static const struct usb_device_id dongles[] = { - /* KingSun Co,Ltd IrDA/USB Bridge */ - {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, dongles); - -#define KINGSUN_MTT 0x07 -#define KINGSUN_REQ_RECV 0x01 -#define KINGSUN_REQ_SEND 0x09 - -#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */ -#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ -#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */ - -struct ks959_speedparams { - __le32 baudrate; /* baud rate, little endian */ - __u8 flags; - __u8 reserved[3]; -} __packed; - -#define KS_DATA_5_BITS 0x00 -#define KS_DATA_6_BITS 0x01 -#define KS_DATA_7_BITS 0x02 -#define KS_DATA_8_BITS 0x03 - -#define KS_STOP_BITS_1 0x00 -#define KS_STOP_BITS_2 0x08 - -#define KS_PAR_DISABLE 0x00 -#define KS_PAR_EVEN 0x10 -#define KS_PAR_ODD 0x30 -#define KS_RESET 0x80 - -struct ks959_cb { - struct usb_device *usbdev; /* init: probe_irda */ - struct net_device *netdev; /* network layer */ - struct irlap_cb *irlap; /* The link layer we are binded to */ - - struct qos_info qos; - - struct usb_ctrlrequest *tx_setuprequest; - struct urb *tx_urb; - __u8 *tx_buf_clear; - unsigned int tx_buf_clear_used; - unsigned int tx_buf_clear_sent; - __u8 *tx_buf_xored; - - struct usb_ctrlrequest *rx_setuprequest; - struct urb *rx_urb; - __u8 *rx_buf; - __u8 rx_variable_xormask; - iobuff_t rx_unwrap_buff; - - struct usb_ctrlrequest *speed_setuprequest; - struct urb *speed_urb; - struct ks959_speedparams speedparams; - unsigned int new_speed; - - spinlock_t lock; - int receiving; -}; - -/* Procedure to perform the obfuscation/padding expected by the dongle - * - * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit - * len_cleartext (IN) Length of the cleartext version of IrDA frame - * buf_xoredtext (OUT) Obfuscated version of frame built by proc - * len_maxbuf (OUT) Maximum space available at buf_xoredtext - * - * (return) length of obfuscated frame with padding - * - * If not enough space (as indicated by len_maxbuf vs. required padding), - * zero is returned - * - * The value of lookup_string is actually a required portion of the algorithm. - * Seems the designer of the dongle wanted to state who exactly is responsible - * for implementing obfuscation. Send your best (or other) wishes to him ]:-) - */ -static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext, - unsigned int len_cleartext, - __u8 * buf_xoredtext, - unsigned int len_maxbuf) -{ - unsigned int len_xoredtext; - - /* Calculate required length with padding, check for necessary space */ - len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10; - if (len_xoredtext <= len_maxbuf) { - static const __u8 lookup_string[] = "wangshuofei19710"; - __u8 xor_mask; - - /* Unlike the WinXP driver, we *do* clear out the padding */ - memset(buf_xoredtext, 0, len_xoredtext); - - xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55; - - while (len_cleartext-- > 0) { - *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask; - } - } else { - len_xoredtext = 0; - } - return len_xoredtext; -} - -/* Callback transmission routine */ -static void ks959_speed_irq(struct urb *urb) -{ - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - dev_err(&urb->dev->dev, - "ks959_speed_irq: urb asynchronously failed - %d\n", - urb->status); - } -} - -/* Send a control request to change speed of the dongle */ -static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed) -{ - static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, - 57600, 115200, 576000, 1152000, 4000000, 0 - }; - int err; - unsigned int i; - - if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) - return -ENOMEM; - - /* Check that requested speed is among the supported ones */ - for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; - if (supported_speeds[i] == 0) - return -EOPNOTSUPP; - - memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams)); - kingsun->speedparams.baudrate = cpu_to_le32(speed); - kingsun->speedparams.flags = KS_DATA_8_BITS; - - /* speed_setuprequest pre-filled in ks959_probe */ - usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, - usb_sndctrlpipe(kingsun->usbdev, 0), - (unsigned char *)kingsun->speed_setuprequest, - &(kingsun->speedparams), - sizeof(struct ks959_speedparams), ks959_speed_irq, - kingsun); - kingsun->speed_urb->status = 0; - err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); - - return err; -} - -/* Submit one fragment of an IrDA frame to the dongle */ -static void ks959_send_irq(struct urb *urb); -static int ks959_submit_tx_fragment(struct ks959_cb *kingsun) -{ - unsigned int padlen; - unsigned int wraplen; - int ret; - - /* Check whether current plaintext can produce a padded buffer that fits - within the range handled by the dongle */ - wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10; - if (wraplen > kingsun->tx_buf_clear_used) - wraplen = kingsun->tx_buf_clear_used; - - /* Perform dongle obfuscation. Also remove the portion of the frame that - was just obfuscated and will now be sent to the dongle. */ - padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen, - kingsun->tx_buf_xored, - KINGSUN_SND_PACKET_SIZE); - - /* Calculate how much data can be transmitted in this urb */ - kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen); - kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen); - /* Rest of the fields were filled in ks959_probe */ - usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev, - usb_sndctrlpipe(kingsun->usbdev, 0), - (unsigned char *)kingsun->tx_setuprequest, - kingsun->tx_buf_xored, padlen, - ks959_send_irq, kingsun); - kingsun->tx_urb->status = 0; - ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); - - /* Remember how much data was sent, in order to update at callback */ - kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; - return ret; -} - -/* Callback transmission routine */ -static void ks959_send_irq(struct urb *urb) -{ - struct ks959_cb *kingsun = urb->context; - struct net_device *netdev = kingsun->netdev; - int ret = 0; - - /* in process of stopping, just drop data */ - if (!netif_running(kingsun->netdev)) { - dev_err(&kingsun->usbdev->dev, - "ks959_send_irq: Network not running!\n"); - return; - } - - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - dev_err(&kingsun->usbdev->dev, - "ks959_send_irq: urb asynchronously failed - %d\n", - urb->status); - return; - } - - if (kingsun->tx_buf_clear_used > 0) { - /* Update data remaining to be sent */ - if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { - memmove(kingsun->tx_buf_clear, - kingsun->tx_buf_clear + - kingsun->tx_buf_clear_sent, - kingsun->tx_buf_clear_used - - kingsun->tx_buf_clear_sent); - } - kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; - kingsun->tx_buf_clear_sent = 0; - - if (kingsun->tx_buf_clear_used > 0) { - /* There is more data to be sent */ - if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { - dev_err(&kingsun->usbdev->dev, - "ks959_send_irq: failed tx_urb submit: %d\n", - ret); - switch (ret) { - case -ENODEV: - case -EPIPE: - break; - default: - netdev->stats.tx_errors++; - netif_start_queue(netdev); - } - } - } else { - /* All data sent, send next speed && wake network queue */ - if (kingsun->new_speed != -1 && - cpu_to_le32(kingsun->new_speed) != - kingsun->speedparams.baudrate) - ks959_change_speed(kingsun, kingsun->new_speed); - - netif_wake_queue(netdev); - } - } -} - -/* - * Called from net/core when new frame is available. - */ -static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct ks959_cb *kingsun; - unsigned int wraplen; - int ret = 0; - - netif_stop_queue(netdev); - - /* the IRDA wrapping routines don't deal with non linear skb */ - SKB_LINEAR_ASSERT(skb); - - kingsun = netdev_priv(netdev); - - spin_lock(&kingsun->lock); - kingsun->new_speed = irda_get_next_speed(skb); - - /* Append data to the end of whatever data remains to be transmitted */ - wraplen = - async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); - kingsun->tx_buf_clear_used = wraplen; - - if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) { - dev_err(&kingsun->usbdev->dev, - "ks959_hard_xmit: failed tx_urb submit: %d\n", ret); - switch (ret) { - case -ENODEV: - case -EPIPE: - break; - default: - netdev->stats.tx_errors++; - netif_start_queue(netdev); - } - } else { - netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; - - } - - dev_kfree_skb(skb); - spin_unlock(&kingsun->lock); - - return NETDEV_TX_OK; -} - -/* Receive callback function */ -static void ks959_rcv_irq(struct urb *urb) -{ - struct ks959_cb *kingsun = urb->context; - int ret; - - /* in process of stopping, just drop data */ - if (!netif_running(kingsun->netdev)) { - kingsun->receiving = 0; - return; - } - - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - dev_err(&kingsun->usbdev->dev, - "kingsun_rcv_irq: urb asynchronously failed - %d\n", - urb->status); - kingsun->receiving = 0; - return; - } - - if (urb->actual_length > 0) { - __u8 *bytes = urb->transfer_buffer; - unsigned int i; - - for (i = 0; i < urb->actual_length; i++) { - /* De-obfuscation implemented here: variable portion of - xormask is incremented, and then used with the encoded - byte for the XOR. The result of the operation is used - to unwrap the SIR frame. */ - kingsun->rx_variable_xormask++; - bytes[i] = - bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u; - - /* rx_variable_xormask doubles as an index counter so we - can skip the byte at 0xff (wrapped around to 0). - */ - if (kingsun->rx_variable_xormask != 0) { - async_unwrap_char(kingsun->netdev, - &kingsun->netdev->stats, - &kingsun->rx_unwrap_buff, - bytes[i]); - } - } - kingsun->receiving = - (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; - } - - /* This urb has already been filled in kingsun_net_open. Setup - packet must be re-filled, but it is assumed that urb keeps the - pointer to the initial setup packet, as well as the payload buffer. - Setup packet is already pre-filled at ks959_probe. - */ - urb->status = 0; - ret = usb_submit_urb(urb, GFP_ATOMIC); -} - -/* - * Function kingsun_net_open (dev) - * - * Network device is taken up. Usually this is done by "ifconfig irda0 up" - */ -static int ks959_net_open(struct net_device *netdev) -{ - struct ks959_cb *kingsun = netdev_priv(netdev); - int err = -ENOMEM; - char hwname[16]; - - /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */ - kingsun->receiving = 0; - - /* Initialize for SIR to copy data directly into skb. */ - kingsun->rx_unwrap_buff.in_frame = FALSE; - kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; - kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; - kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (!kingsun->rx_unwrap_buff.skb) - goto free_mem; - - skb_reserve(kingsun->rx_unwrap_buff.skb, 1); - kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; - - kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->rx_urb) - goto free_mem; - - kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->tx_urb) - goto free_mem; - - kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->speed_urb) - goto free_mem; - - /* Initialize speed for dongle */ - kingsun->new_speed = 9600; - err = ks959_change_speed(kingsun, 9600); - if (err < 0) - goto free_mem; - - /* - * Now that everything should be initialized properly, - * Open new IrLAP layer instance to take care of us... - */ - sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); - kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); - if (!kingsun->irlap) { - err = -ENOMEM; - dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); - goto free_mem; - } - - /* Start reception. Setup request already pre-filled in ks959_probe */ - usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev, - usb_rcvctrlpipe(kingsun->usbdev, 0), - (unsigned char *)kingsun->rx_setuprequest, - kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE, - ks959_rcv_irq, kingsun); - kingsun->rx_urb->status = 0; - err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); - if (err) { - dev_err(&kingsun->usbdev->dev, - "first urb-submit failed: %d\n", err); - goto close_irlap; - } - - netif_start_queue(netdev); - - /* Situation at this point: - - all work buffers allocated - - urbs allocated and ready to fill - - max rx packet known (in max_rx) - - unwrap state machine initialized, in state outside of any frame - - receive request in progress - - IrLAP layer started, about to hand over packets to send - */ - - return 0; - - close_irlap: - irlap_close(kingsun->irlap); - free_mem: - usb_free_urb(kingsun->speed_urb); - kingsun->speed_urb = NULL; - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - if (kingsun->rx_unwrap_buff.skb) { - kfree_skb(kingsun->rx_unwrap_buff.skb); - kingsun->rx_unwrap_buff.skb = NULL; - kingsun->rx_unwrap_buff.head = NULL; - } - return err; -} - -/* - * Function kingsun_net_close (kingsun) - * - * Network device is taken down. Usually this is done by - * "ifconfig irda0 down" - */ -static int ks959_net_close(struct net_device *netdev) -{ - struct ks959_cb *kingsun = netdev_priv(netdev); - - /* Stop transmit processing */ - netif_stop_queue(netdev); - - /* Mop up receive && transmit urb's */ - usb_kill_urb(kingsun->tx_urb); - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - - usb_kill_urb(kingsun->speed_urb); - usb_free_urb(kingsun->speed_urb); - kingsun->speed_urb = NULL; - - usb_kill_urb(kingsun->rx_urb); - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - - kfree_skb(kingsun->rx_unwrap_buff.skb); - kingsun->rx_unwrap_buff.skb = NULL; - kingsun->rx_unwrap_buff.head = NULL; - kingsun->rx_unwrap_buff.in_frame = FALSE; - kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; - kingsun->receiving = 0; - - /* Stop and remove instance of IrLAP */ - if (kingsun->irlap) - irlap_close(kingsun->irlap); - - kingsun->irlap = NULL; - - return 0; -} - -/* - * IOCTLs : Extra out-of-band network commands... - */ -static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *)rq; - struct ks959_cb *kingsun = netdev_priv(netdev); - int ret = 0; - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the device is still there */ - if (netif_device_present(kingsun->netdev)) - return ks959_change_speed(kingsun, irq->ifr_baudrate); - break; - - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the IrDA stack is still there */ - if (netif_running(kingsun->netdev)) - irda_device_set_media_busy(kingsun->netdev, TRUE); - break; - - case SIOCGRECEIVING: - /* Only approximately true */ - irq->ifr_receiving = kingsun->receiving; - break; - - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -static const struct net_device_ops ks959_ops = { - .ndo_start_xmit = ks959_hard_xmit, - .ndo_open = ks959_net_open, - .ndo_stop = ks959_net_close, - .ndo_do_ioctl = ks959_net_ioctl, -}; -/* - * This routine is called by the USB subsystem for each new device - * in the system. We need to check if the device is ours, and in - * this case start handling it. - */ -static int ks959_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct ks959_cb *kingsun = NULL; - struct net_device *net = NULL; - int ret = -ENOMEM; - - /* Allocate network device container. */ - net = alloc_irdadev(sizeof(*kingsun)); - if (!net) - goto err_out1; - - SET_NETDEV_DEV(net, &intf->dev); - kingsun = netdev_priv(net); - kingsun->netdev = net; - kingsun->usbdev = dev; - kingsun->irlap = NULL; - kingsun->tx_setuprequest = NULL; - kingsun->tx_urb = NULL; - kingsun->tx_buf_clear = NULL; - kingsun->tx_buf_xored = NULL; - kingsun->tx_buf_clear_used = 0; - kingsun->tx_buf_clear_sent = 0; - - kingsun->rx_setuprequest = NULL; - kingsun->rx_urb = NULL; - kingsun->rx_buf = NULL; - kingsun->rx_variable_xormask = 0; - kingsun->rx_unwrap_buff.in_frame = FALSE; - kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; - kingsun->rx_unwrap_buff.skb = NULL; - kingsun->receiving = 0; - spin_lock_init(&kingsun->lock); - - kingsun->speed_setuprequest = NULL; - kingsun->speed_urb = NULL; - kingsun->speedparams.baudrate = 0; - - /* Allocate input buffer */ - kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL); - if (!kingsun->rx_buf) - goto free_mem; - - /* Allocate input setup packet */ - kingsun->rx_setuprequest = - kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!kingsun->rx_setuprequest) - goto free_mem; - kingsun->rx_setuprequest->bRequestType = - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV; - kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200); - kingsun->rx_setuprequest->wIndex = 0; - kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE); - - /* Allocate output buffer */ - kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); - if (!kingsun->tx_buf_clear) - goto free_mem; - kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL); - if (!kingsun->tx_buf_xored) - goto free_mem; - - /* Allocate and initialize output setup packet */ - kingsun->tx_setuprequest = - kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!kingsun->tx_setuprequest) - goto free_mem; - kingsun->tx_setuprequest->bRequestType = - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND; - kingsun->tx_setuprequest->wValue = 0; - kingsun->tx_setuprequest->wIndex = 0; - kingsun->tx_setuprequest->wLength = 0; - - /* Allocate and initialize speed setup packet */ - kingsun->speed_setuprequest = - kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!kingsun->speed_setuprequest) - goto free_mem; - kingsun->speed_setuprequest->bRequestType = - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; - kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); - kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); - kingsun->speed_setuprequest->wLength = - cpu_to_le16(sizeof(struct ks959_speedparams)); - - printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, " - "Vendor: %x, Product: %x\n", - dev->devnum, le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&kingsun->qos); - - /* Baud rates known to be supported. Please uncomment if devices (other - than a SonyEriccson K300 phone) can be shown to support higher speed - with this dongle. - */ - kingsun->qos.baud_rate.bits = - IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600; - kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; - irda_qos_bits_to_value(&kingsun->qos); - - /* Override the network functions we need to use */ - net->netdev_ops = &ks959_ops; - - ret = register_netdev(net); - if (ret != 0) - goto free_mem; - - dev_info(&net->dev, "IrDA: Registered KingSun KS-959 device %s\n", - net->name); - - usb_set_intfdata(intf, kingsun); - - /* Situation at this point: - - all work buffers allocated - - setup requests pre-filled - - urbs not allocated, set to NULL - - max rx packet known (is KINGSUN_FIFO_SIZE) - - unwrap state machine (partially) initialized, but skb == NULL - */ - - return 0; - - free_mem: - kfree(kingsun->speed_setuprequest); - kfree(kingsun->tx_setuprequest); - kfree(kingsun->tx_buf_xored); - kfree(kingsun->tx_buf_clear); - kfree(kingsun->rx_setuprequest); - kfree(kingsun->rx_buf); - free_netdev(net); - err_out1: - return ret; -} - -/* - * The current device is removed, the USB layer tell us to shut it down... - */ -static void ks959_disconnect(struct usb_interface *intf) -{ - struct ks959_cb *kingsun = usb_get_intfdata(intf); - - if (!kingsun) - return; - - unregister_netdev(kingsun->netdev); - - /* Mop up receive && transmit urb's */ - if (kingsun->speed_urb != NULL) { - usb_kill_urb(kingsun->speed_urb); - usb_free_urb(kingsun->speed_urb); - kingsun->speed_urb = NULL; - } - if (kingsun->tx_urb != NULL) { - usb_kill_urb(kingsun->tx_urb); - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - } - if (kingsun->rx_urb != NULL) { - usb_kill_urb(kingsun->rx_urb); - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - } - - kfree(kingsun->speed_setuprequest); - kfree(kingsun->tx_setuprequest); - kfree(kingsun->tx_buf_xored); - kfree(kingsun->tx_buf_clear); - kfree(kingsun->rx_setuprequest); - kfree(kingsun->rx_buf); - free_netdev(kingsun->netdev); - - usb_set_intfdata(intf, NULL); -} - -#ifdef CONFIG_PM -/* USB suspend, so power off the transmitter/receiver */ -static int ks959_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct ks959_cb *kingsun = usb_get_intfdata(intf); - - netif_device_detach(kingsun->netdev); - if (kingsun->speed_urb != NULL) - usb_kill_urb(kingsun->speed_urb); - if (kingsun->tx_urb != NULL) - usb_kill_urb(kingsun->tx_urb); - if (kingsun->rx_urb != NULL) - usb_kill_urb(kingsun->rx_urb); - return 0; -} - -/* Coming out of suspend, so reset hardware */ -static int ks959_resume(struct usb_interface *intf) -{ - struct ks959_cb *kingsun = usb_get_intfdata(intf); - - if (kingsun->rx_urb != NULL) { - /* Setup request already filled in ks959_probe */ - usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); - } - netif_device_attach(kingsun->netdev); - - return 0; -} -#endif - -/* - * USB device callbacks - */ -static struct usb_driver irda_driver = { - .name = "ks959-sir", - .probe = ks959_probe, - .disconnect = ks959_disconnect, - .id_table = dongles, -#ifdef CONFIG_PM - .suspend = ks959_suspend, - .resume = ks959_resume, -#endif -}; - -module_usb_driver(irda_driver); - -MODULE_AUTHOR("Alex VillacÃs Lasso <a_villacis@palosanto.com>"); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/ksdazzle-sir.c b/drivers/staging/irda/drivers/ksdazzle-sir.c deleted file mode 100644 index d2a0755df596..000000000000 --- a/drivers/staging/irda/drivers/ksdazzle-sir.c +++ /dev/null @@ -1,813 +0,0 @@ -/***************************************************************************** -* -* Filename: ksdazzle.c -* Version: 0.1.2 -* Description: Irda KingSun Dazzle USB Dongle -* Status: Experimental -* Author: Alex VillacÃs Lasso <a_villacis@palosanto.com> -* -* Based on stir4200, mcs7780, kingsun-sir drivers. -* -* 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. -* -* 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. -* -*****************************************************************************/ - -/* - * Following is my most current (2007-07-26) understanding of how the Kingsun - * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This - * information was deduced by examining the USB traffic captured with USBSnoopy - * from the WinXP driver. Feel free to update here as more of the dongle is - * known. - * - * General: This dongle exposes one interface with two interrupt endpoints, one - * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine - * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and - * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir. - * - * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then - * split it into multiple segments of up to 7 bytes each, and transmit each in - * sequence. It seems that sending a single big block (like kingsun-sir does) - * won't work with this dongle. Each segment needs to be prefixed with a value - * equal to (unsigned char)0xF8 + <number of bytes in segment>, inside a payload - * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9, - * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the - * payload, not considered by the prefix, are ignored (set to 0 by this - * implementation). - * - * Reception: To receive data, the driver must poll the dongle regularly (like - * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned - * in payloads from 0 to 8 bytes long. When concatenated, these payloads form - * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir - * - * Speed change: To change the speed of the dongle, the driver prepares a - * control URB with the following as a setup packet: - * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE - * bRequest 0x09 - * wValue 0x0200 - * wIndex 0x0001 - * wLength 0x0008 (length of the payload) - * The payload is a 8-byte record, apparently identical to the one used in - * drivers/usb/serial/cypress_m8.c to change speed: - * __u32 baudSpeed; - * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits - * unsigned int : 1; - * unsigned int stopBits : 1; - * unsigned int parityEnable : 1; - * unsigned int parityType : 1; - * unsigned int : 1; - * unsigned int reset : 1; - * unsigned char reserved[3]; // set to 0 - * - * For now only SIR speeds have been observed with this dongle. Therefore, - * nothing is known on what changes (if any) must be done to frame wrapping / - * unwrapping for higher than SIR speeds. This driver assumes no change is - * necessary and announces support for all the way to 115200 bps. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/device.h> -#include <linux/crc32.h> - -#include <asm/unaligned.h> -#include <asm/byteorder.h> -#include <linux/uaccess.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/crc.h> - -#define KSDAZZLE_VENDOR_ID 0x07d0 -#define KSDAZZLE_PRODUCT_ID 0x4100 - -/* These are the currently known USB ids */ -static const struct usb_device_id dongles[] = { - /* KingSun Co,Ltd IrDA/USB Bridge */ - {USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, dongles); - -#define KINGSUN_MTT 0x07 -#define KINGSUN_REQ_RECV 0x01 -#define KINGSUN_REQ_SEND 0x09 - -#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */ -#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */ - -struct ksdazzle_speedparams { - __le32 baudrate; /* baud rate, little endian */ - __u8 flags; - __u8 reserved[3]; -} __packed; - -#define KS_DATA_5_BITS 0x00 -#define KS_DATA_6_BITS 0x01 -#define KS_DATA_7_BITS 0x02 -#define KS_DATA_8_BITS 0x03 - -#define KS_STOP_BITS_1 0x00 -#define KS_STOP_BITS_2 0x08 - -#define KS_PAR_DISABLE 0x00 -#define KS_PAR_EVEN 0x10 -#define KS_PAR_ODD 0x30 -#define KS_RESET 0x80 - -#define KINGSUN_EP_IN 0 -#define KINGSUN_EP_OUT 1 - -struct ksdazzle_cb { - struct usb_device *usbdev; /* init: probe_irda */ - struct net_device *netdev; /* network layer */ - struct irlap_cb *irlap; /* The link layer we are binded to */ - - struct qos_info qos; - - struct urb *tx_urb; - __u8 *tx_buf_clear; - unsigned int tx_buf_clear_used; - unsigned int tx_buf_clear_sent; - __u8 tx_payload[8]; - - struct urb *rx_urb; - __u8 *rx_buf; - iobuff_t rx_unwrap_buff; - - struct usb_ctrlrequest *speed_setuprequest; - struct urb *speed_urb; - struct ksdazzle_speedparams speedparams; - unsigned int new_speed; - - __u8 ep_in; - __u8 ep_out; - - spinlock_t lock; - int receiving; -}; - -/* Callback transmission routine */ -static void ksdazzle_speed_irq(struct urb *urb) -{ - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) - dev_err(&urb->dev->dev, - "ksdazzle_speed_irq: urb asynchronously failed - %d\n", - urb->status); -} - -/* Send a control request to change speed of the dongle */ -static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed) -{ - static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400, - 57600, 115200, 576000, 1152000, 4000000, 0 - }; - int err; - unsigned int i; - - if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL) - return -ENOMEM; - - /* Check that requested speed is among the supported ones */ - for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ; - if (supported_speeds[i] == 0) - return -EOPNOTSUPP; - - memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams)); - kingsun->speedparams.baudrate = cpu_to_le32(speed); - kingsun->speedparams.flags = KS_DATA_8_BITS; - - /* speed_setuprequest pre-filled in ksdazzle_probe */ - usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev, - usb_sndctrlpipe(kingsun->usbdev, 0), - (unsigned char *)kingsun->speed_setuprequest, - &(kingsun->speedparams), - sizeof(struct ksdazzle_speedparams), - ksdazzle_speed_irq, kingsun); - kingsun->speed_urb->status = 0; - err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC); - - return err; -} - -/* Submit one fragment of an IrDA frame to the dongle */ -static void ksdazzle_send_irq(struct urb *urb); -static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun) -{ - unsigned int wraplen; - int ret; - - /* We can send at most 7 bytes of payload at a time */ - wraplen = 7; - if (wraplen > kingsun->tx_buf_clear_used) - wraplen = kingsun->tx_buf_clear_used; - - /* Prepare payload prefix with used length */ - memset(kingsun->tx_payload, 0, 8); - kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen; - memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen); - - usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev, - usb_sndintpipe(kingsun->usbdev, kingsun->ep_out), - kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1); - kingsun->tx_urb->status = 0; - ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC); - - /* Remember how much data was sent, in order to update at callback */ - kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0; - return ret; -} - -/* Callback transmission routine */ -static void ksdazzle_send_irq(struct urb *urb) -{ - struct ksdazzle_cb *kingsun = urb->context; - struct net_device *netdev = kingsun->netdev; - int ret = 0; - - /* in process of stopping, just drop data */ - if (!netif_running(kingsun->netdev)) { - dev_err(&kingsun->usbdev->dev, - "ksdazzle_send_irq: Network not running!\n"); - return; - } - - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - dev_err(&kingsun->usbdev->dev, - "ksdazzle_send_irq: urb asynchronously failed - %d\n", - urb->status); - return; - } - - if (kingsun->tx_buf_clear_used > 0) { - /* Update data remaining to be sent */ - if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) { - memmove(kingsun->tx_buf_clear, - kingsun->tx_buf_clear + - kingsun->tx_buf_clear_sent, - kingsun->tx_buf_clear_used - - kingsun->tx_buf_clear_sent); - } - kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent; - kingsun->tx_buf_clear_sent = 0; - - if (kingsun->tx_buf_clear_used > 0) { - /* There is more data to be sent */ - if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { - dev_err(&kingsun->usbdev->dev, - "ksdazzle_send_irq: failed tx_urb submit: %d\n", - ret); - switch (ret) { - case -ENODEV: - case -EPIPE: - break; - default: - netdev->stats.tx_errors++; - netif_start_queue(netdev); - } - } - } else { - /* All data sent, send next speed && wake network queue */ - if (kingsun->new_speed != -1 && - cpu_to_le32(kingsun->new_speed) != - kingsun->speedparams.baudrate) - ksdazzle_change_speed(kingsun, - kingsun->new_speed); - - netif_wake_queue(netdev); - } - } -} - -/* - * Called from net/core when new frame is available. - */ -static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct ksdazzle_cb *kingsun; - unsigned int wraplen; - int ret = 0; - - netif_stop_queue(netdev); - - /* the IRDA wrapping routines don't deal with non linear skb */ - SKB_LINEAR_ASSERT(skb); - - kingsun = netdev_priv(netdev); - - spin_lock(&kingsun->lock); - kingsun->new_speed = irda_get_next_speed(skb); - - /* Append data to the end of whatever data remains to be transmitted */ - wraplen = - async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE); - kingsun->tx_buf_clear_used = wraplen; - - if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) { - dev_err(&kingsun->usbdev->dev, - "ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret); - switch (ret) { - case -ENODEV: - case -EPIPE: - break; - default: - netdev->stats.tx_errors++; - netif_start_queue(netdev); - } - } else { - netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; - - } - - dev_kfree_skb(skb); - spin_unlock(&kingsun->lock); - - return NETDEV_TX_OK; -} - -/* Receive callback function */ -static void ksdazzle_rcv_irq(struct urb *urb) -{ - struct ksdazzle_cb *kingsun = urb->context; - struct net_device *netdev = kingsun->netdev; - - /* in process of stopping, just drop data */ - if (!netif_running(netdev)) { - kingsun->receiving = 0; - return; - } - - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) { - dev_err(&kingsun->usbdev->dev, - "ksdazzle_rcv_irq: urb asynchronously failed - %d\n", - urb->status); - kingsun->receiving = 0; - return; - } - - if (urb->actual_length > 0) { - __u8 *bytes = urb->transfer_buffer; - unsigned int i; - - for (i = 0; i < urb->actual_length; i++) { - async_unwrap_char(netdev, &netdev->stats, - &kingsun->rx_unwrap_buff, bytes[i]); - } - kingsun->receiving = - (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; - } - - /* This urb has already been filled in ksdazzle_net_open. It is assumed that - urb keeps the pointer to the payload buffer. - */ - urb->status = 0; - usb_submit_urb(urb, GFP_ATOMIC); -} - -/* - * Function ksdazzle_net_open (dev) - * - * Network device is taken up. Usually this is done by "ifconfig irda0 up" - */ -static int ksdazzle_net_open(struct net_device *netdev) -{ - struct ksdazzle_cb *kingsun = netdev_priv(netdev); - int err = -ENOMEM; - char hwname[16]; - - /* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */ - kingsun->receiving = 0; - - /* Initialize for SIR to copy data directly into skb. */ - kingsun->rx_unwrap_buff.in_frame = FALSE; - kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; - kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU; - kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (!kingsun->rx_unwrap_buff.skb) - goto free_mem; - - skb_reserve(kingsun->rx_unwrap_buff.skb, 1); - kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data; - - kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->rx_urb) - goto free_mem; - - kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->tx_urb) - goto free_mem; - - kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!kingsun->speed_urb) - goto free_mem; - - /* Initialize speed for dongle */ - kingsun->new_speed = 9600; - err = ksdazzle_change_speed(kingsun, 9600); - if (err < 0) - goto free_mem; - - /* - * Now that everything should be initialized properly, - * Open new IrLAP layer instance to take care of us... - */ - sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); - kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); - if (!kingsun->irlap) { - err = -ENOMEM; - dev_err(&kingsun->usbdev->dev, "irlap_open failed\n"); - goto free_mem; - } - - /* Start reception. */ - usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, - usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), - kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq, - kingsun, 1); - kingsun->rx_urb->status = 0; - err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); - if (err) { - dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err); - goto close_irlap; - } - - netif_start_queue(netdev); - - /* Situation at this point: - - all work buffers allocated - - urbs allocated and ready to fill - - max rx packet known (in max_rx) - - unwrap state machine initialized, in state outside of any frame - - receive request in progress - - IrLAP layer started, about to hand over packets to send - */ - - return 0; - - close_irlap: - irlap_close(kingsun->irlap); - free_mem: - usb_free_urb(kingsun->speed_urb); - kingsun->speed_urb = NULL; - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - if (kingsun->rx_unwrap_buff.skb) { - kfree_skb(kingsun->rx_unwrap_buff.skb); - kingsun->rx_unwrap_buff.skb = NULL; - kingsun->rx_unwrap_buff.head = NULL; - } - return err; -} - -/* - * Function ksdazzle_net_close (dev) - * - * Network device is taken down. Usually this is done by - * "ifconfig irda0 down" - */ -static int ksdazzle_net_close(struct net_device *netdev) -{ - struct ksdazzle_cb *kingsun = netdev_priv(netdev); - - /* Stop transmit processing */ - netif_stop_queue(netdev); - - /* Mop up receive && transmit urb's */ - usb_kill_urb(kingsun->tx_urb); - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - - usb_kill_urb(kingsun->speed_urb); - usb_free_urb(kingsun->speed_urb); - kingsun->speed_urb = NULL; - - usb_kill_urb(kingsun->rx_urb); - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - - kfree_skb(kingsun->rx_unwrap_buff.skb); - kingsun->rx_unwrap_buff.skb = NULL; - kingsun->rx_unwrap_buff.head = NULL; - kingsun->rx_unwrap_buff.in_frame = FALSE; - kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; - kingsun->receiving = 0; - - /* Stop and remove instance of IrLAP */ - irlap_close(kingsun->irlap); - - kingsun->irlap = NULL; - - return 0; -} - -/* - * IOCTLs : Extra out-of-band network commands... - */ -static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq, - int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *)rq; - struct ksdazzle_cb *kingsun = netdev_priv(netdev); - int ret = 0; - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the device is still there */ - if (netif_device_present(kingsun->netdev)) - return ksdazzle_change_speed(kingsun, - irq->ifr_baudrate); - break; - - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the IrDA stack is still there */ - if (netif_running(kingsun->netdev)) - irda_device_set_media_busy(kingsun->netdev, TRUE); - break; - - case SIOCGRECEIVING: - /* Only approximately true */ - irq->ifr_receiving = kingsun->receiving; - break; - - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -static const struct net_device_ops ksdazzle_ops = { - .ndo_start_xmit = ksdazzle_hard_xmit, - .ndo_open = ksdazzle_net_open, - .ndo_stop = ksdazzle_net_close, - .ndo_do_ioctl = ksdazzle_net_ioctl, -}; - -/* - * This routine is called by the USB subsystem for each new device - * in the system. We need to check if the device is ours, and in - * this case start handling it. - */ -static int ksdazzle_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_host_interface *interface; - struct usb_endpoint_descriptor *endpoint; - - struct usb_device *dev = interface_to_usbdev(intf); - struct ksdazzle_cb *kingsun = NULL; - struct net_device *net = NULL; - int ret = -ENOMEM; - int pipe, maxp_in, maxp_out; - __u8 ep_in; - __u8 ep_out; - - /* Check that there really are two interrupt endpoints. Check based on the - one in drivers/usb/input/usbmouse.c - */ - interface = intf->cur_altsetting; - if (interface->desc.bNumEndpoints != 2) { - dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n", - interface->desc.bNumEndpoints); - return -ENODEV; - } - endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; - if (!usb_endpoint_is_int_in(endpoint)) { - dev_err(&intf->dev, - "ksdazzle: endpoint 0 is not interrupt IN\n"); - return -ENODEV; - } - - ep_in = endpoint->bEndpointAddress; - pipe = usb_rcvintpipe(dev, ep_in); - maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - if (maxp_in > 255 || maxp_in <= 1) { - dev_err(&intf->dev, - "ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n", - maxp_in); - return -ENODEV; - } - - endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; - if (!usb_endpoint_is_int_out(endpoint)) { - dev_err(&intf->dev, - "ksdazzle: endpoint 1 is not interrupt OUT\n"); - return -ENODEV; - } - - ep_out = endpoint->bEndpointAddress; - pipe = usb_sndintpipe(dev, ep_out); - maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - /* Allocate network device container. */ - net = alloc_irdadev(sizeof(*kingsun)); - if (!net) - goto err_out1; - - SET_NETDEV_DEV(net, &intf->dev); - kingsun = netdev_priv(net); - kingsun->netdev = net; - kingsun->usbdev = dev; - kingsun->ep_in = ep_in; - kingsun->ep_out = ep_out; - kingsun->irlap = NULL; - kingsun->tx_urb = NULL; - kingsun->tx_buf_clear = NULL; - kingsun->tx_buf_clear_used = 0; - kingsun->tx_buf_clear_sent = 0; - - kingsun->rx_urb = NULL; - kingsun->rx_buf = NULL; - kingsun->rx_unwrap_buff.in_frame = FALSE; - kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME; - kingsun->rx_unwrap_buff.skb = NULL; - kingsun->receiving = 0; - spin_lock_init(&kingsun->lock); - - kingsun->speed_setuprequest = NULL; - kingsun->speed_urb = NULL; - kingsun->speedparams.baudrate = 0; - - /* Allocate input buffer */ - kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL); - if (!kingsun->rx_buf) - goto free_mem; - - /* Allocate output buffer */ - kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL); - if (!kingsun->tx_buf_clear) - goto free_mem; - - /* Allocate and initialize speed setup packet */ - kingsun->speed_setuprequest = - kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!kingsun->speed_setuprequest) - goto free_mem; - kingsun->speed_setuprequest->bRequestType = - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND; - kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200); - kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001); - kingsun->speed_setuprequest->wLength = - cpu_to_le16(sizeof(struct ksdazzle_speedparams)); - - printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, " - "Vendor: %x, Product: %x\n", - dev->devnum, le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&kingsun->qos); - - /* Baud rates known to be supported. Please uncomment if devices (other - than a SonyEriccson K300 phone) can be shown to support higher speeds - with this dongle. - */ - kingsun->qos.baud_rate.bits = - IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200; - kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; - irda_qos_bits_to_value(&kingsun->qos); - - /* Override the network functions we need to use */ - net->netdev_ops = &ksdazzle_ops; - - ret = register_netdev(net); - if (ret != 0) - goto free_mem; - - dev_info(&net->dev, "IrDA: Registered KingSun/Dazzle device %s\n", - net->name); - - usb_set_intfdata(intf, kingsun); - - /* Situation at this point: - - all work buffers allocated - - setup requests pre-filled - - urbs not allocated, set to NULL - - max rx packet known (is KINGSUN_FIFO_SIZE) - - unwrap state machine (partially) initialized, but skb == NULL - */ - - return 0; - - free_mem: - kfree(kingsun->speed_setuprequest); - kfree(kingsun->tx_buf_clear); - kfree(kingsun->rx_buf); - free_netdev(net); - err_out1: - return ret; -} - -/* - * The current device is removed, the USB layer tell us to shut it down... - */ -static void ksdazzle_disconnect(struct usb_interface *intf) -{ - struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); - - if (!kingsun) - return; - - unregister_netdev(kingsun->netdev); - - /* Mop up receive && transmit urb's */ - usb_kill_urb(kingsun->speed_urb); - usb_free_urb(kingsun->speed_urb); - kingsun->speed_urb = NULL; - - usb_kill_urb(kingsun->tx_urb); - usb_free_urb(kingsun->tx_urb); - kingsun->tx_urb = NULL; - - usb_kill_urb(kingsun->rx_urb); - usb_free_urb(kingsun->rx_urb); - kingsun->rx_urb = NULL; - - kfree(kingsun->speed_setuprequest); - kfree(kingsun->tx_buf_clear); - kfree(kingsun->rx_buf); - free_netdev(kingsun->netdev); - - usb_set_intfdata(intf, NULL); -} - -#ifdef CONFIG_PM -/* USB suspend, so power off the transmitter/receiver */ -static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); - - netif_device_detach(kingsun->netdev); - if (kingsun->speed_urb != NULL) - usb_kill_urb(kingsun->speed_urb); - if (kingsun->tx_urb != NULL) - usb_kill_urb(kingsun->tx_urb); - if (kingsun->rx_urb != NULL) - usb_kill_urb(kingsun->rx_urb); - return 0; -} - -/* Coming out of suspend, so reset hardware */ -static int ksdazzle_resume(struct usb_interface *intf) -{ - struct ksdazzle_cb *kingsun = usb_get_intfdata(intf); - - if (kingsun->rx_urb != NULL) { - /* Setup request already filled in ksdazzle_probe */ - usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); - } - netif_device_attach(kingsun->netdev); - - return 0; -} -#endif - -/* - * USB device callbacks - */ -static struct usb_driver irda_driver = { - .name = "ksdazzle-sir", - .probe = ksdazzle_probe, - .disconnect = ksdazzle_disconnect, - .id_table = dongles, -#ifdef CONFIG_PM - .suspend = ksdazzle_suspend, - .resume = ksdazzle_resume, -#endif -}; - -module_usb_driver(irda_driver); - -MODULE_AUTHOR("Alex VillacÃs Lasso <a_villacis@palosanto.com>"); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/litelink-sir.c b/drivers/staging/irda/drivers/litelink-sir.c deleted file mode 100644 index 8eefcb44bac3..000000000000 --- a/drivers/staging/irda/drivers/litelink-sir.c +++ /dev/null @@ -1,199 +0,0 @@ -/********************************************************************* - * - * Filename: litelink.c - * Version: 1.1 - * Description: Driver for the Parallax LiteLink dongle - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri May 7 12:50:33 1999 - * Modified at: Fri Dec 17 09:14:23 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -/* - * Modified at: Thu Jan 15 2003 - * Modified by: Eugene Crosser <crosser@average.org> - * - * Convert to "new" IRDA infrastructure for kernel 2.6 - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ -#define MAX_DELAY 10000 /* 1 ms */ - -static int litelink_open(struct sir_dev *dev); -static int litelink_close(struct sir_dev *dev); -static int litelink_change_speed(struct sir_dev *dev, unsigned speed); -static int litelink_reset(struct sir_dev *dev); - -/* These are the baudrates supported - 9600 must be last one! */ -static unsigned baud_rates[] = { 115200, 57600, 38400, 19200, 9600 }; - -static struct dongle_driver litelink = { - .owner = THIS_MODULE, - .driver_name = "Parallax LiteLink", - .type = IRDA_LITELINK_DONGLE, - .open = litelink_open, - .close = litelink_close, - .reset = litelink_reset, - .set_speed = litelink_change_speed, -}; - -static int __init litelink_sir_init(void) -{ - return irda_register_dongle(&litelink); -} - -static void __exit litelink_sir_cleanup(void) -{ - irda_unregister_dongle(&litelink); -} - -static int litelink_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - /* Power up dongle */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Set the speeds we can accept */ - qos->baud_rate.bits &= IR_115200|IR_57600|IR_38400|IR_19200|IR_9600; - qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int litelink_close(struct sir_dev *dev) -{ - /* Power off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function litelink_change_speed (task) - * - * Change speed of the Litelink dongle. To cycle through the available - * baud rates, pulse RTS low for a few ms. - */ -static int litelink_change_speed(struct sir_dev *dev, unsigned speed) -{ - int i; - - /* dongle already reset by irda-thread - current speed (dongle and - * port) is the default speed (115200 for litelink!) - */ - - /* Cycle through avaiable baudrates until we reach the correct one */ - for (i = 0; baud_rates[i] != speed; i++) { - - /* end-of-list reached due to invalid speed request */ - if (baud_rates[i] == 9600) - break; - - /* Set DTR, clear RTS */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Set DTR, Set RTS */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - } - - dev->speed = baud_rates[i]; - - /* invalid baudrate should not happen - but if, we return -EINVAL and - * the dongle configured for 9600 so the stack has a chance to recover - */ - - return (dev->speed == speed) ? 0 : -EINVAL; -} - -/* - * Function litelink_reset (task) - * - * Reset the Litelink type dongle. - * - */ -static int litelink_reset(struct sir_dev *dev) -{ - /* probably the power-up can be dropped here, but with only - * 15 usec delay it's not worth the risk unless somebody with - * the hardware confirms it doesn't break anything... - */ - - /* Power on dongle */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Clear RTS to reset dongle */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* This dongles speed defaults to 115200 bps */ - dev->speed = 115200; - - return 0; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Parallax Litelink dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-5"); /* IRDA_LITELINK_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize Litelink module - * - */ -module_init(litelink_sir_init); - -/* - * Function cleanup_module (void) - * - * Cleanup Litelink module - * - */ -module_exit(litelink_sir_cleanup); diff --git a/drivers/staging/irda/drivers/ma600-sir.c b/drivers/staging/irda/drivers/ma600-sir.c deleted file mode 100644 index a764817b47f1..000000000000 --- a/drivers/staging/irda/drivers/ma600-sir.c +++ /dev/null @@ -1,253 +0,0 @@ -/********************************************************************* - * - * Filename: ma600.c - * Version: 0.1 - * Description: Implementation of the MA600 dongle - * Status: Experimental. - * Author: Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95 - * Created at: Sat Jun 10 20:02:35 2000 - * Modified at: Sat Aug 16 09:34:13 2003 - * Modified by: Martin Diehl <mad@mdiehl.de> (modified for new sir_dev) - * - * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing - * information on the MA600 dongle - * - * Copyright (c) 2000 Leung, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -static int ma600_open(struct sir_dev *); -static int ma600_close(struct sir_dev *); -static int ma600_change_speed(struct sir_dev *, unsigned); -static int ma600_reset(struct sir_dev *); - -/* control byte for MA600 */ -#define MA600_9600 0x00 -#define MA600_19200 0x01 -#define MA600_38400 0x02 -#define MA600_57600 0x03 -#define MA600_115200 0x04 -#define MA600_DEV_ID1 0x05 -#define MA600_DEV_ID2 0x06 -#define MA600_2400 0x08 - -static struct dongle_driver ma600 = { - .owner = THIS_MODULE, - .driver_name = "MA600", - .type = IRDA_MA600_DONGLE, - .open = ma600_open, - .close = ma600_close, - .reset = ma600_reset, - .set_speed = ma600_change_speed, -}; - - -static int __init ma600_sir_init(void) -{ - return irda_register_dongle(&ma600); -} - -static void __exit ma600_sir_cleanup(void) -{ - irda_unregister_dongle(&ma600); -} - -/* - Power on: - (0) Clear RTS and DTR for 1 second - (1) Set RTS and DTR for 1 second - (2) 9600 bps now - Note: assume RTS, DTR are clear before -*/ -static int ma600_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Explicitly set the speeds we can accept */ - qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400 - |IR_57600|IR_115200; - /* Hm, 0x01 means 10ms - for >= 1ms we would need 0x07 */ - qos->min_turn_time.bits = 0x01; /* Needs at least 1 ms */ - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int ma600_close(struct sir_dev *dev) -{ - /* Power off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -static __u8 get_control_byte(__u32 speed) -{ - __u8 byte; - - switch (speed) { - default: - case 115200: - byte = MA600_115200; - break; - case 57600: - byte = MA600_57600; - break; - case 38400: - byte = MA600_38400; - break; - case 19200: - byte = MA600_19200; - break; - case 9600: - byte = MA600_9600; - break; - case 2400: - byte = MA600_2400; - break; - } - - return byte; -} - -/* - * Function ma600_change_speed (dev, speed) - * - * Set the speed for the MA600 type dongle. - * - * The dongle has already been reset to a known state (dongle default) - * We cycle through speeds by pulsing RTS low and then high. - */ - -/* - * Function ma600_change_speed (dev, speed) - * - * Set the speed for the MA600 type dongle. - * - * Algorithm - * 1. Reset (already done by irda thread state machine) - * 2. clear RTS, set DTR and wait for 1ms - * 3. send Control Byte to the MA600 through TXD to set new baud rate - * wait until the stop bit of Control Byte is sent (for 9600 baud rate, - * it takes about 10 msec) - * 4. set RTS, set DTR (return to NORMAL Operation) - * 5. wait at least 10 ms, new setting (baud rate, etc) takes effect here - * after - */ - -/* total delays are only about 20ms - let's just sleep for now to - * avoid the state machine complexity before we get things working - */ - -static int ma600_change_speed(struct sir_dev *dev, unsigned speed) -{ - u8 byte; - - pr_debug("%s(), speed=%d (was %d)\n", __func__, - speed, dev->speed); - - /* dongle already reset, dongle and port at default speed (9600) */ - - /* Set RTS low for 1 ms */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - mdelay(1); - - /* Write control byte */ - byte = get_control_byte(speed); - sirdev_raw_write(dev, &byte, sizeof(byte)); - - /* Wait at least 10ms: fake wait_until_sent - 10 bits at 9600 baud*/ - msleep(15); /* old ma600 uses 15ms */ - -#if 1 - /* read-back of the control byte. ma600 is the first dongle driver - * which uses this so there might be some unidentified issues. - * Disable this in case of problems with readback. - */ - - sirdev_raw_read(dev, &byte, sizeof(byte)); - if (byte != get_control_byte(speed)) { - net_warn_ratelimited("%s(): bad control byte read-back %02x != %02x\n", - __func__, (unsigned)byte, - (unsigned)get_control_byte(speed)); - return -1; - } - else - pr_debug("%s() control byte write read OK\n", __func__); -#endif - - /* Set DTR, Set RTS */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Wait at least 10ms */ - msleep(10); - - /* dongle is now switched to the new speed */ - dev->speed = speed; - - return 0; -} - -/* - * Function ma600_reset (dev) - * - * This function resets the ma600 dongle. - * - * Algorithm: - * 0. DTR=0, RTS=1 and wait 10 ms - * 1. DTR=1, RTS=1 and wait 10 ms - * 2. 9600 bps now - */ - -/* total delays are only about 20ms - let's just sleep for now to - * avoid the state machine complexity before we get things working - */ - -static int ma600_reset(struct sir_dev *dev) -{ - /* Reset the dongle : set DTR low for 10 ms */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - msleep(10); - - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - msleep(10); - - dev->speed = 9600; /* That's the dongle-default */ - - return 0; -} - -MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95"); -MODULE_DESCRIPTION("MA600 dongle driver version 0.1"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-11"); /* IRDA_MA600_DONGLE */ - -module_init(ma600_sir_init); -module_exit(ma600_sir_cleanup); - diff --git a/drivers/staging/irda/drivers/mcp2120-sir.c b/drivers/staging/irda/drivers/mcp2120-sir.c deleted file mode 100644 index 2e33f91bfe8f..000000000000 --- a/drivers/staging/irda/drivers/mcp2120-sir.c +++ /dev/null @@ -1,224 +0,0 @@ -/********************************************************************* - * - * - * Filename: mcp2120.c - * Version: 1.0 - * Description: Implementation for the MCP2120 (Microchip) - * Status: Experimental. - * Author: Felix Tang (tangf@eyetap.org) - * Created at: Sun Mar 31 19:32:12 EST 2002 - * Based on code by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 2002 Felix Tang, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -static int mcp2120_reset(struct sir_dev *dev); -static int mcp2120_open(struct sir_dev *dev); -static int mcp2120_close(struct sir_dev *dev); -static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed); - -#define MCP2120_9600 0x87 -#define MCP2120_19200 0x8B -#define MCP2120_38400 0x85 -#define MCP2120_57600 0x83 -#define MCP2120_115200 0x81 - -#define MCP2120_COMMIT 0x11 - -static struct dongle_driver mcp2120 = { - .owner = THIS_MODULE, - .driver_name = "Microchip MCP2120", - .type = IRDA_MCP2120_DONGLE, - .open = mcp2120_open, - .close = mcp2120_close, - .reset = mcp2120_reset, - .set_speed = mcp2120_change_speed, -}; - -static int __init mcp2120_sir_init(void) -{ - return irda_register_dongle(&mcp2120); -} - -static void __exit mcp2120_sir_cleanup(void) -{ - irda_unregister_dongle(&mcp2120); -} - -static int mcp2120_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - /* seems no explicit power-on required here and reset switching it on anyway */ - - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x01; - irda_qos_bits_to_value(qos); - - return 0; -} - -static int mcp2120_close(struct sir_dev *dev) -{ - /* Power off dongle */ - /* reset and inhibit mcp2120 */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - // sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function mcp2120_change_speed (dev, speed) - * - * Set the speed for the MCP2120. - * - */ - -#define MCP2120_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED+1) - -static int mcp2120_change_speed(struct sir_dev *dev, unsigned speed) -{ - unsigned state = dev->fsm.substate; - unsigned delay = 0; - u8 control[2]; - static int ret = 0; - - switch (state) { - case SIRDEV_STATE_DONGLE_SPEED: - /* Set DTR to enter command mode */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - udelay(500); - - ret = 0; - switch (speed) { - default: - speed = 9600; - ret = -EINVAL; - /* fall through */ - case 9600: - control[0] = MCP2120_9600; - //printk("mcp2120 9600\n"); - break; - case 19200: - control[0] = MCP2120_19200; - //printk("mcp2120 19200\n"); - break; - case 34800: - control[0] = MCP2120_38400; - //printk("mcp2120 38400\n"); - break; - case 57600: - control[0] = MCP2120_57600; - //printk("mcp2120 57600\n"); - break; - case 115200: - control[0] = MCP2120_115200; - //printk("mcp2120 115200\n"); - break; - } - control[1] = MCP2120_COMMIT; - - /* Write control bytes */ - sirdev_raw_write(dev, control, 2); - dev->speed = speed; - - state = MCP2120_STATE_WAIT_SPEED; - delay = 100; - //printk("mcp2120_change_speed: dongle_speed\n"); - break; - - case MCP2120_STATE_WAIT_SPEED: - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - //printk("mcp2120_change_speed: mcp_wait\n"); - break; - - default: - net_err_ratelimited("%s(), undefine state %d\n", - __func__, state); - ret = -EINVAL; - break; - } - dev->fsm.substate = state; - return (delay > 0) ? delay : ret; -} - -/* - * Function mcp2120_reset (driver) - * - * This function resets the mcp2120 dongle. - * - * Info: -set RTS to reset mcp2120 - * -set DTR to set mcp2120 software command mode - * -mcp2120 defaults to 9600 baud after reset - * - * Algorithm: - * 0. Set RTS to reset mcp2120. - * 1. Clear RTS and wait for device reset timer of 30 ms (max). - * - */ - -#define MCP2120_STATE_WAIT1_RESET (SIRDEV_STATE_DONGLE_RESET+1) -#define MCP2120_STATE_WAIT2_RESET (SIRDEV_STATE_DONGLE_RESET+2) - -static int mcp2120_reset(struct sir_dev *dev) -{ - unsigned state = dev->fsm.substate; - unsigned delay = 0; - int ret = 0; - - switch (state) { - case SIRDEV_STATE_DONGLE_RESET: - //printk("mcp2120_reset: dongle_reset\n"); - /* Reset dongle by setting RTS*/ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - state = MCP2120_STATE_WAIT1_RESET; - delay = 50; - break; - - case MCP2120_STATE_WAIT1_RESET: - //printk("mcp2120_reset: mcp2120_wait1\n"); - /* clear RTS and wait for at least 30 ms. */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - state = MCP2120_STATE_WAIT2_RESET; - delay = 50; - break; - - case MCP2120_STATE_WAIT2_RESET: - //printk("mcp2120_reset mcp2120_wait2\n"); - /* Go back to normal mode */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - break; - - default: - net_err_ratelimited("%s(), undefined state %d\n", - __func__, state); - ret = -EINVAL; - break; - } - dev->fsm.substate = state; - return (delay > 0) ? delay : ret; -} - -MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>"); -MODULE_DESCRIPTION("Microchip MCP2120"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */ - -module_init(mcp2120_sir_init); -module_exit(mcp2120_sir_cleanup); diff --git a/drivers/staging/irda/drivers/mcs7780.c b/drivers/staging/irda/drivers/mcs7780.c deleted file mode 100644 index d52e9f4b9770..000000000000 --- a/drivers/staging/irda/drivers/mcs7780.c +++ /dev/null @@ -1,990 +0,0 @@ -/***************************************************************************** -* -* Filename: mcs7780.c -* Version: 0.4-alpha -* Description: Irda MosChip USB Dongle Driver -* Authors: Lukasz Stelmach <stlman@poczta.fm> -* Brian Pugh <bpugh@cs.pdx.edu> -* Judy Fischbach <jfisch@cs.pdx.edu> -* -* Based on stir4200 driver, but some things done differently. -* Based on earlier driver by Paul Stewart <stewart@parc.com> -* -* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> -* Copyright (C) 2001, Dag Brattli <dag@brattli.net> -* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> -* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> -* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm> -* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu> -* Copyright (C) 2005, Judy Fischbach <jfisch@cs.pdx.edu> -* -* 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. -* -*****************************************************************************/ - -/* - * MCS7780 is a simple USB to IrDA bridge by MosChip. It is neither - * compatibile with irda-usb nor with stir4200. Although it is quite - * similar to the later as far as general idea of operation is concerned. - * That is it requires the software to do all the framing job at SIR speeds. - * The hardware does take care of the framing at MIR and FIR speeds. - * It supports all speeds from 2400 through 4Mbps - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/device.h> -#include <linux/crc32.h> - -#include <asm/unaligned.h> -#include <asm/byteorder.h> -#include <linux/uaccess.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/crc.h> - -#include "mcs7780.h" - -#define MCS_VENDOR_ID 0x9710 -#define MCS_PRODUCT_ID 0x7780 - -static const struct usb_device_id mcs_table[] = { - /* MosChip Corp., MCS7780 FIR-USB Adapter */ - {USB_DEVICE(MCS_VENDOR_ID, MCS_PRODUCT_ID)}, - {}, -}; - -MODULE_AUTHOR("Brian Pugh <bpugh@cs.pdx.edu>"); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver for MosChip MCS7780"); -MODULE_VERSION("0.3alpha"); -MODULE_LICENSE("GPL"); - -MODULE_DEVICE_TABLE(usb, mcs_table); - -static int qos_mtt_bits = 0x07 /* > 1ms */ ; -module_param(qos_mtt_bits, int, 0); -MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); - -static int receive_mode = 0x1; -module_param(receive_mode, int, 0); -MODULE_PARM_DESC(receive_mode, - "Receive mode of the device (1:fast, 0:slow, default:1)"); - -static int sir_tweak = 1; -module_param(sir_tweak, int, 0444); -MODULE_PARM_DESC(sir_tweak, - "Default pulse width (1:1.6us, 0:3/16 bit, default:1)."); - -static int transceiver_type = MCS_TSC_VISHAY; -module_param(transceiver_type, int, 0444); -MODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h."); - -static struct usb_driver mcs_driver = { - .name = "mcs7780", - .probe = mcs_probe, - .disconnect = mcs_disconnect, - .id_table = mcs_table, -}; - -/* speed flag selection by direct addressing. -addr = (speed >> 8) & 0x0f - -0x1 57600 0x2 115200 0x4 1152000 0x5 9600 -0x6 38400 0x9 2400 0xa 576000 0xb 19200 - -4Mbps (or 2400) must be checked separately. Since it also has -to be programmed in a different manner that is not a big problem. -*/ -static __u16 mcs_speed_set[16] = { 0, - MCS_SPEED_57600, - MCS_SPEED_115200, - 0, - MCS_SPEED_1152000, - MCS_SPEED_9600, - MCS_SPEED_38400, - 0, 0, - MCS_SPEED_2400, - MCS_SPEED_576000, - MCS_SPEED_19200, - 0, 0, 0, -}; - -/* Set given 16 bit register with a 16 bit value. Send control message - * to set dongle register. */ -static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val) -{ - struct usb_device *dev = mcs->usbdev; - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, - MCS_WR_RTYPE, val, reg, NULL, 0, - msecs_to_jiffies(MCS_CTRL_TIMEOUT)); -} - -/* Get 16 bit register value. Send contol message to read dongle register. */ -static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val) -{ - struct usb_device *dev = mcs->usbdev; - void *dmabuf; - int ret; - - dmabuf = kmalloc(sizeof(__u16), GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; - - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, - MCS_RD_RTYPE, 0, reg, dmabuf, 2, - msecs_to_jiffies(MCS_CTRL_TIMEOUT)); - - memcpy(val, dmabuf, sizeof(__u16)); - kfree(dmabuf); - - return ret; -} - -/* Setup a communication between mcs7780 and TFDU chips. It is described - * in more detail in the data sheet. The setup sequence puts the the - * vishay tranceiver into high speed mode. It will also receive SIR speed - * packets but at reduced sensitivity. - */ - -/* 0: OK 1:ERROR */ -static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs) -{ - int ret = 0; - __u16 rval; - - /* mcs_get_reg should read exactly two bytes from the dongle */ - ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval); - if (unlikely(ret != 2)) { - ret = -EIO; - goto error; - } - - /* The MCS_XCVR_CONF bit puts the transceiver into configuration - * mode. The MCS_MODE0 bit must start out high (1) and then - * transition to low and the MCS_STFIR and MCS_MODE1 bits must - * be low. - */ - rval |= (MCS_MODE0 | MCS_XCVR_CONF); - rval &= ~MCS_STFIR; - rval &= ~MCS_MODE1; - ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); - if (unlikely(ret)) - goto error; - - rval &= ~MCS_MODE0; - ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); - if (unlikely(ret)) - goto error; - - rval &= ~MCS_XCVR_CONF; - ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); - if (unlikely(ret)) - goto error; - - ret = 0; -error: - return ret; -} - -/* Setup a communication between mcs7780 and agilent chip. */ -static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs) -{ - net_warn_ratelimited("This transceiver type is not supported yet\n"); - return 1; -} - -/* Setup a communication between mcs7780 and sharp chip. */ -static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs) -{ - net_warn_ratelimited("This transceiver type is not supported yet\n"); - return 1; -} - -/* Common setup for all transceivers */ -static inline int mcs_setup_transceiver(struct mcs_cb *mcs) -{ - int ret = 0; - __u16 rval; - const char *msg; - - msg = "Basic transceiver setup error"; - - /* read value of MODE Register, set the DRIVER and RESET bits - * and write value back out to MODE Register - */ - ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); - if(unlikely(ret != 2)) - goto error; - rval |= MCS_DRIVER; /* put the mcs7780 into configuration mode. */ - ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); - if(unlikely(ret)) - goto error; - - rval = 0; /* set min pulse width to 0 initially. */ - ret = mcs_set_reg(mcs, MCS_MINRXPW_REG, rval); - if(unlikely(ret)) - goto error; - - ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); - if(unlikely(ret != 2)) - goto error; - - rval &= ~MCS_FIR; /* turn off fir mode. */ - if(mcs->sir_tweak) - rval |= MCS_SIR16US; /* 1.6us pulse width */ - else - rval &= ~MCS_SIR16US; /* 3/16 bit time pulse width */ - - /* make sure ask mode and back to back packets are off. */ - rval &= ~(MCS_BBTG | MCS_ASK); - - rval &= ~MCS_SPEED_MASK; - rval |= MCS_SPEED_9600; /* make sure initial speed is 9600. */ - mcs->speed = 9600; - mcs->new_speed = 0; /* new_speed is set to 0 */ - rval &= ~MCS_PLLPWDN; /* disable power down. */ - - /* make sure device determines direction and that the auto send sip - * pulse are on. - */ - rval |= MCS_DTD | MCS_SIPEN; - - ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); - if(unlikely(ret)) - goto error; - - msg = "transceiver model specific setup error"; - switch (mcs->transceiver_type) { - case MCS_TSC_VISHAY: - ret = mcs_setup_transceiver_vishay(mcs); - break; - - case MCS_TSC_SHARP: - ret = mcs_setup_transceiver_sharp(mcs); - break; - - case MCS_TSC_AGILENT: - ret = mcs_setup_transceiver_agilent(mcs); - break; - - default: - net_warn_ratelimited("Unknown transceiver type: %d\n", - mcs->transceiver_type); - ret = 1; - } - if (unlikely(ret)) - goto error; - - /* If transceiver is not SHARP, then if receive mode set - * on the RXFAST bit in the XCVR Register otherwise unset it - */ - if (mcs->transceiver_type != MCS_TSC_SHARP) { - - ret = mcs_get_reg(mcs, MCS_XCVR_REG, &rval); - if (unlikely(ret != 2)) - goto error; - if (mcs->receive_mode) - rval |= MCS_RXFAST; - else - rval &= ~MCS_RXFAST; - ret = mcs_set_reg(mcs, MCS_XCVR_REG, rval); - if (unlikely(ret)) - goto error; - } - - msg = "transceiver reset"; - - ret = mcs_get_reg(mcs, MCS_MODE_REG, &rval); - if (unlikely(ret != 2)) - goto error; - - /* reset the mcs7780 so all changes take effect. */ - rval &= ~MCS_RESET; - ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); - if (unlikely(ret)) - goto error; - else - return ret; - -error: - net_err_ratelimited("%s\n", msg); - return ret; -} - -/* Wraps the data in format for SIR */ -static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf) -{ - int wraplen; - - /* 2: full frame length, including "the length" */ - wraplen = async_wrap_skb(skb, buf + 2, 4094); - - wraplen += 2; - buf[0] = wraplen & 0xff; - buf[1] = (wraplen >> 8) & 0xff; - - return wraplen; -} - -/* Wraps the data in format for FIR */ -static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf) -{ - unsigned int len = 0; - __u32 fcs = ~(crc32_le(~0, skb->data, skb->len)); - - /* add 2 bytes for length value and 4 bytes for fcs. */ - len = skb->len + 6; - - /* The mcs7780 requires that the first two bytes are the packet - * length in little endian order. Note: the length value includes - * the two bytes for the length value itself. - */ - buf[0] = len & 0xff; - buf[1] = (len >> 8) & 0xff; - /* copy the data into the tx buffer. */ - skb_copy_from_linear_data(skb, buf + 2, skb->len); - /* put the fcs in the last four bytes in little endian order. */ - buf[len - 4] = fcs & 0xff; - buf[len - 3] = (fcs >> 8) & 0xff; - buf[len - 2] = (fcs >> 16) & 0xff; - buf[len - 1] = (fcs >> 24) & 0xff; - - return len; -} - -/* Wraps the data in format for MIR */ -static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf) -{ - __u16 fcs = 0; - int len = skb->len + 4; - - fcs = ~(irda_calc_crc16(~fcs, skb->data, skb->len)); - /* put the total packet length in first. Note: packet length - * value includes the two bytes that hold the packet length - * itself. - */ - buf[0] = len & 0xff; - buf[1] = (len >> 8) & 0xff; - /* copy the data */ - skb_copy_from_linear_data(skb, buf + 2, skb->len); - /* put the fcs in last two bytes in little endian order. */ - buf[len - 2] = fcs & 0xff; - buf[len - 1] = (fcs >> 8) & 0xff; - - return len; -} - -/* Unwrap received packets at MIR speed. A 16 bit crc_ccitt checksum is - * used for the fcs. When performed over the entire packet the result - * should be GOOD_FCS = 0xf0b8. Hands the unwrapped data off to the IrDA - * layer via a sk_buff. - */ -static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len) -{ - __u16 fcs; - int new_len; - struct sk_buff *skb; - - /* Assume that the frames are going to fill a single packet - * rather than span multiple packets. - */ - - new_len = len - 2; - if(unlikely(new_len <= 0)) { - net_err_ratelimited("%s short frame length %d\n", - mcs->netdev->name, new_len); - ++mcs->netdev->stats.rx_errors; - ++mcs->netdev->stats.rx_length_errors; - return; - } - fcs = 0; - fcs = irda_calc_crc16(~fcs, buf, len); - - if(fcs != GOOD_FCS) { - net_err_ratelimited("crc error calc 0x%x len %d\n", - fcs, new_len); - mcs->netdev->stats.rx_errors++; - mcs->netdev->stats.rx_crc_errors++; - return; - } - - skb = dev_alloc_skb(new_len + 1); - if(unlikely(!skb)) { - ++mcs->netdev->stats.rx_dropped; - return; - } - - skb_reserve(skb, 1); - skb_copy_to_linear_data(skb, buf, new_len); - skb_put(skb, new_len); - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - skb->dev = mcs->netdev; - - netif_rx(skb); - - mcs->netdev->stats.rx_packets++; - mcs->netdev->stats.rx_bytes += new_len; -} - -/* Unwrap received packets at FIR speed. A 32 bit crc_ccitt checksum is - * used for the fcs. Hands the unwrapped data off to the IrDA - * layer via a sk_buff. - */ -static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) -{ - __u32 fcs; - int new_len; - struct sk_buff *skb; - - /* Assume that the frames are going to fill a single packet - * rather than span multiple packets. This is most likely a false - * assumption. - */ - - new_len = len - 4; - if(unlikely(new_len <= 0)) { - net_err_ratelimited("%s short frame length %d\n", - mcs->netdev->name, new_len); - ++mcs->netdev->stats.rx_errors; - ++mcs->netdev->stats.rx_length_errors; - return; - } - - fcs = ~(crc32_le(~0, buf, new_len)); - if(fcs != get_unaligned_le32(buf + new_len)) { - net_err_ratelimited("crc error calc 0x%x len %d\n", - fcs, new_len); - mcs->netdev->stats.rx_errors++; - mcs->netdev->stats.rx_crc_errors++; - return; - } - - skb = dev_alloc_skb(new_len + 1); - if(unlikely(!skb)) { - ++mcs->netdev->stats.rx_dropped; - return; - } - - skb_reserve(skb, 1); - skb_copy_to_linear_data(skb, buf, new_len); - skb_put(skb, new_len); - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - skb->dev = mcs->netdev; - - netif_rx(skb); - - mcs->netdev->stats.rx_packets++; - mcs->netdev->stats.rx_bytes += new_len; -} - - -/* Allocates urbs for both receive and transmit. - * If alloc fails return error code 0 (fail) otherwise - * return error code 1 (success). - */ -static inline int mcs_setup_urbs(struct mcs_cb *mcs) -{ - mcs->rx_urb = NULL; - - mcs->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!mcs->tx_urb) - return 0; - - mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!mcs->rx_urb) { - usb_free_urb(mcs->tx_urb); - mcs->tx_urb = NULL; - return 0; - } - - return 1; -} - -/* Sets up state to be initially outside frame, gets receive urb, - * sets status to successful and then submits the urb to start - * receiving the data. - */ -static inline int mcs_receive_start(struct mcs_cb *mcs) -{ - mcs->rx_buff.in_frame = FALSE; - mcs->rx_buff.state = OUTSIDE_FRAME; - - usb_fill_bulk_urb(mcs->rx_urb, mcs->usbdev, - usb_rcvbulkpipe(mcs->usbdev, mcs->ep_in), - mcs->in_buf, 4096, mcs_receive_irq, mcs); - - mcs->rx_urb->status = 0; - return usb_submit_urb(mcs->rx_urb, GFP_KERNEL); -} - -/* Finds the in and out endpoints for the mcs control block */ -static inline int mcs_find_endpoints(struct mcs_cb *mcs, - struct usb_host_endpoint *ep, int epnum) -{ - int i; - int ret = 0; - - /* If no place to store the endpoints just return */ - if (!ep) - return ret; - - /* cycle through all endpoints, find the first two that are DIR_IN */ - for (i = 0; i < epnum; i++) { - if (ep[i].desc.bEndpointAddress & USB_DIR_IN) - mcs->ep_in = ep[i].desc.bEndpointAddress; - else - mcs->ep_out = ep[i].desc.bEndpointAddress; - - /* MosChip says that the chip has only two bulk - * endpoints. Find one for each direction and move on. - */ - if ((mcs->ep_in != 0) && (mcs->ep_out != 0)) { - ret = 1; - break; - } - } - - return ret; -} - -static void mcs_speed_work(struct work_struct *work) -{ - struct mcs_cb *mcs = container_of(work, struct mcs_cb, work); - struct net_device *netdev = mcs->netdev; - - mcs_speed_change(mcs); - netif_wake_queue(netdev); -} - -/* Function to change the speed of the mcs7780. Fully supports SIR, - * MIR, and FIR speeds. - */ -static int mcs_speed_change(struct mcs_cb *mcs) -{ - int ret = 0; - int rst = 0; - int cnt = 0; - __u16 nspeed; - __u16 rval; - - nspeed = mcs_speed_set[(mcs->new_speed >> 8) & 0x0f]; - - do { - mcs_get_reg(mcs, MCS_RESV_REG, &rval); - } while(cnt++ < 100 && (rval & MCS_IRINTX)); - - if (cnt > 100) { - net_err_ratelimited("unable to change speed\n"); - ret = -EIO; - goto error; - } - - mcs_get_reg(mcs, MCS_MODE_REG, &rval); - - /* MINRXPW values recommended by MosChip */ - if (mcs->new_speed <= 115200) { - rval &= ~MCS_FIR; - - rst = mcs->speed > 115200; - if (rst) - mcs_set_reg(mcs, MCS_MINRXPW_REG, 0); - - } else if (mcs->new_speed <= 1152000) { - rval &= ~MCS_FIR; - - rst = !(mcs->speed == 576000 || mcs->speed == 1152000); - if (rst) - mcs_set_reg(mcs, MCS_MINRXPW_REG, 5); - - } else { - rval |= MCS_FIR; - - rst = mcs->speed != 4000000; - if (rst) - mcs_set_reg(mcs, MCS_MINRXPW_REG, 5); - - } - - rval &= ~MCS_SPEED_MASK; - rval |= nspeed; - - ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); - if (unlikely(ret)) - goto error; - - if (rst) - switch (mcs->transceiver_type) { - case MCS_TSC_VISHAY: - ret = mcs_setup_transceiver_vishay(mcs); - break; - - case MCS_TSC_SHARP: - ret = mcs_setup_transceiver_sharp(mcs); - break; - - case MCS_TSC_AGILENT: - ret = mcs_setup_transceiver_agilent(mcs); - break; - - default: - ret = 1; - net_warn_ratelimited("Unknown transceiver type: %d\n", - mcs->transceiver_type); - } - if (unlikely(ret)) - goto error; - - mcs_get_reg(mcs, MCS_MODE_REG, &rval); - rval &= ~MCS_RESET; - ret = mcs_set_reg(mcs, MCS_MODE_REG, rval); - - mcs->speed = mcs->new_speed; -error: - mcs->new_speed = 0; - return ret; -} - -/* Ioctl calls not supported at this time. Can be an area of future work. */ -static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -{ - /* struct if_irda_req *irq = (struct if_irda_req *)rq; */ - /* struct mcs_cb *mcs = netdev_priv(netdev); */ - int ret = 0; - - switch (cmd) { - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -/* Network device is taken down, done by "ifconfig irda0 down" */ -static int mcs_net_close(struct net_device *netdev) -{ - int ret = 0; - struct mcs_cb *mcs = netdev_priv(netdev); - - /* Stop transmit processing */ - netif_stop_queue(netdev); - - kfree_skb(mcs->rx_buff.skb); - - /* kill and free the receive and transmit URBs */ - usb_kill_urb(mcs->rx_urb); - usb_free_urb(mcs->rx_urb); - usb_kill_urb(mcs->tx_urb); - usb_free_urb(mcs->tx_urb); - - /* Stop and remove instance of IrLAP */ - if (mcs->irlap) - irlap_close(mcs->irlap); - - mcs->irlap = NULL; - return ret; -} - -/* Network device is taken up, done by "ifconfig irda0 up" */ -static int mcs_net_open(struct net_device *netdev) -{ - struct mcs_cb *mcs = netdev_priv(netdev); - char hwname[16]; - int ret = 0; - - ret = usb_clear_halt(mcs->usbdev, - usb_sndbulkpipe(mcs->usbdev, mcs->ep_in)); - if (ret) - goto error1; - ret = usb_clear_halt(mcs->usbdev, - usb_rcvbulkpipe(mcs->usbdev, mcs->ep_out)); - if (ret) - goto error1; - - ret = mcs_setup_transceiver(mcs); - if (ret) - goto error1; - - ret = -ENOMEM; - - /* Initialize for SIR/FIR to copy data directly into skb. */ - mcs->receiving = 0; - mcs->rx_buff.truesize = IRDA_SKB_MAX_MTU; - mcs->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (!mcs->rx_buff.skb) - goto error1; - - skb_reserve(mcs->rx_buff.skb, 1); - mcs->rx_buff.head = mcs->rx_buff.skb->data; - - /* - * Now that everything should be initialized properly, - * Open new IrLAP layer instance to take care of us... - * Note : will send immediately a speed change... - */ - sprintf(hwname, "usb#%d", mcs->usbdev->devnum); - mcs->irlap = irlap_open(netdev, &mcs->qos, hwname); - if (!mcs->irlap) { - net_err_ratelimited("mcs7780: irlap_open failed\n"); - goto error2; - } - - if (!mcs_setup_urbs(mcs)) - goto error3; - - ret = mcs_receive_start(mcs); - if (ret) - goto error4; - - netif_start_queue(netdev); - return 0; - -error4: - usb_free_urb(mcs->rx_urb); - usb_free_urb(mcs->tx_urb); -error3: - irlap_close(mcs->irlap); -error2: - kfree_skb(mcs->rx_buff.skb); -error1: - return ret; -} - -/* Receive callback function. */ -static void mcs_receive_irq(struct urb *urb) -{ - __u8 *bytes; - struct mcs_cb *mcs = urb->context; - int i; - int ret; - - if (!netif_running(mcs->netdev)) - return; - - if (urb->status) - return; - - if (urb->actual_length > 0) { - bytes = urb->transfer_buffer; - - /* MCS returns frames without BOF and EOF - * I assume it returns whole frames. - */ - /* SIR speed */ - if(mcs->speed < 576000) { - async_unwrap_char(mcs->netdev, &mcs->netdev->stats, - &mcs->rx_buff, 0xc0); - - for (i = 0; i < urb->actual_length; i++) - async_unwrap_char(mcs->netdev, &mcs->netdev->stats, - &mcs->rx_buff, bytes[i]); - - async_unwrap_char(mcs->netdev, &mcs->netdev->stats, - &mcs->rx_buff, 0xc1); - } - /* MIR speed */ - else if(mcs->speed == 576000 || mcs->speed == 1152000) { - mcs_unwrap_mir(mcs, urb->transfer_buffer, - urb->actual_length); - } - /* FIR speed */ - else { - mcs_unwrap_fir(mcs, urb->transfer_buffer, - urb->actual_length); - } - } - - ret = usb_submit_urb(urb, GFP_ATOMIC); -} - -/* Transmit callback function. */ -static void mcs_send_irq(struct urb *urb) -{ - struct mcs_cb *mcs = urb->context; - struct net_device *ndev = mcs->netdev; - - if (unlikely(mcs->new_speed)) - schedule_work(&mcs->work); - else - netif_wake_queue(ndev); -} - -/* Transmit callback function. */ -static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, - struct net_device *ndev) -{ - unsigned long flags; - struct mcs_cb *mcs; - int wraplen; - int ret = 0; - - netif_stop_queue(ndev); - mcs = netdev_priv(ndev); - - spin_lock_irqsave(&mcs->lock, flags); - - mcs->new_speed = irda_get_next_speed(skb); - if (likely(mcs->new_speed == mcs->speed)) - mcs->new_speed = 0; - - /* SIR speed */ - if(mcs->speed < 576000) { - wraplen = mcs_wrap_sir_skb(skb, mcs->out_buf); - } - /* MIR speed */ - else if(mcs->speed == 576000 || mcs->speed == 1152000) { - wraplen = mcs_wrap_mir_skb(skb, mcs->out_buf); - } - /* FIR speed */ - else { - wraplen = mcs_wrap_fir_skb(skb, mcs->out_buf); - } - usb_fill_bulk_urb(mcs->tx_urb, mcs->usbdev, - usb_sndbulkpipe(mcs->usbdev, mcs->ep_out), - mcs->out_buf, wraplen, mcs_send_irq, mcs); - - if ((ret = usb_submit_urb(mcs->tx_urb, GFP_ATOMIC))) { - net_err_ratelimited("failed tx_urb: %d\n", ret); - switch (ret) { - case -ENODEV: - case -EPIPE: - break; - default: - mcs->netdev->stats.tx_errors++; - netif_start_queue(ndev); - } - } else { - mcs->netdev->stats.tx_packets++; - mcs->netdev->stats.tx_bytes += skb->len; - } - - dev_kfree_skb(skb); - spin_unlock_irqrestore(&mcs->lock, flags); - return NETDEV_TX_OK; -} - -static const struct net_device_ops mcs_netdev_ops = { - .ndo_open = mcs_net_open, - .ndo_stop = mcs_net_close, - .ndo_start_xmit = mcs_hard_xmit, - .ndo_do_ioctl = mcs_net_ioctl, -}; - -/* - * This function is called by the USB subsystem for each new device in the - * system. Need to verify the device and if it is, then start handling it. - */ -static int mcs_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct net_device *ndev = NULL; - struct mcs_cb *mcs; - int ret = -ENOMEM; - - ndev = alloc_irdadev(sizeof(*mcs)); - if (!ndev) - goto error1; - - pr_debug("MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum); - - SET_NETDEV_DEV(ndev, &intf->dev); - - ret = usb_reset_configuration(udev); - if (ret != 0) { - net_err_ratelimited("mcs7780: usb reset configuration failed\n"); - goto error2; - } - - mcs = netdev_priv(ndev); - mcs->usbdev = udev; - mcs->netdev = ndev; - spin_lock_init(&mcs->lock); - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&mcs->qos); - - /* That's the Rx capability. */ - mcs->qos.baud_rate.bits &= - IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 - | IR_576000 | IR_1152000 | (IR_4000000 << 8); - - - mcs->qos.min_turn_time.bits &= qos_mtt_bits; - irda_qos_bits_to_value(&mcs->qos); - - /* Speed change work initialisation*/ - INIT_WORK(&mcs->work, mcs_speed_work); - - ndev->netdev_ops = &mcs_netdev_ops; - - if (!intf->cur_altsetting) { - ret = -ENOMEM; - goto error2; - } - - ret = mcs_find_endpoints(mcs, intf->cur_altsetting->endpoint, - intf->cur_altsetting->desc.bNumEndpoints); - if (!ret) { - ret = -ENODEV; - goto error2; - } - - ret = register_netdev(ndev); - if (ret != 0) - goto error2; - - pr_debug("IrDA: Registered MosChip MCS7780 device as %s\n", - ndev->name); - - mcs->transceiver_type = transceiver_type; - mcs->sir_tweak = sir_tweak; - mcs->receive_mode = receive_mode; - - usb_set_intfdata(intf, mcs); - return 0; - -error2: - free_netdev(ndev); - -error1: - return ret; -} - -/* The current device is removed, the USB layer tells us to shut down. */ -static void mcs_disconnect(struct usb_interface *intf) -{ - struct mcs_cb *mcs = usb_get_intfdata(intf); - - if (!mcs) - return; - - cancel_work_sync(&mcs->work); - - unregister_netdev(mcs->netdev); - free_netdev(mcs->netdev); - - usb_set_intfdata(intf, NULL); - pr_debug("MCS7780 now disconnected.\n"); -} - -module_usb_driver(mcs_driver); diff --git a/drivers/staging/irda/drivers/mcs7780.h b/drivers/staging/irda/drivers/mcs7780.h deleted file mode 100644 index a6e8f7dbafc9..000000000000 --- a/drivers/staging/irda/drivers/mcs7780.h +++ /dev/null @@ -1,165 +0,0 @@ -/***************************************************************************** -* -* Filename: mcs7780.h -* Version: 0.2-alpha -* Description: Irda MosChip USB Dongle -* Status: Experimental -* Authors: Lukasz Stelmach <stlman@poczta.fm> -* Brian Pugh <bpugh@cs.pdx.edu> -* -* Copyright (C) 2005, Lukasz Stelmach <stlman@poczta.fm> -* Copyright (C) 2005, Brian Pugh <bpugh@cs.pdx.edu> -* -* 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. -* -*****************************************************************************/ -#ifndef _MCS7780_H -#define _MCS7780_H - -#define MCS_MODE_SIR 0 -#define MCS_MODE_MIR 1 -#define MCS_MODE_FIR 2 - -#define MCS_CTRL_TIMEOUT 500 -#define MCS_XMIT_TIMEOUT 500 -/* Possible transceiver types */ -#define MCS_TSC_VISHAY 0 /* Vishay TFD, default choice */ -#define MCS_TSC_AGILENT 1 /* Agilent 3602/3600 */ -#define MCS_TSC_SHARP 2 /* Sharp GP2W1000YP */ - -/* Requests */ -#define MCS_RD_RTYPE 0xC0 -#define MCS_WR_RTYPE 0x40 -#define MCS_RDREQ 0x0F -#define MCS_WRREQ 0x0E - -/* Register 0x00 */ -#define MCS_MODE_REG 0 -#define MCS_FIR ((__u16)0x0001) -#define MCS_SIR16US ((__u16)0x0002) -#define MCS_BBTG ((__u16)0x0004) -#define MCS_ASK ((__u16)0x0008) -#define MCS_PARITY ((__u16)0x0010) - -/* SIR/MIR speed constants */ -#define MCS_SPEED_SHIFT 5 -#define MCS_SPEED_MASK ((__u16)0x00E0) -#define MCS_SPEED(x) ((x & MCS_SPEED_MASK) >> MCS_SPEED_SHIFT) -#define MCS_SPEED_2400 ((0 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) -#define MCS_SPEED_9600 ((1 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) -#define MCS_SPEED_19200 ((2 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) -#define MCS_SPEED_38400 ((3 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) -#define MCS_SPEED_57600 ((4 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) -#define MCS_SPEED_115200 ((5 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) -#define MCS_SPEED_576000 ((6 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) -#define MCS_SPEED_1152000 ((7 << MCS_SPEED_SHIFT) & MCS_SPEED_MASK) - -#define MCS_PLLPWDN ((__u16)0x0100) -#define MCS_DRIVER ((__u16)0x0200) -#define MCS_DTD ((__u16)0x0400) -#define MCS_DIR ((__u16)0x0800) -#define MCS_SIPEN ((__u16)0x1000) -#define MCS_SENDSIP ((__u16)0x2000) -#define MCS_CHGDIR ((__u16)0x4000) -#define MCS_RESET ((__u16)0x8000) - -/* Register 0x02 */ -#define MCS_XCVR_REG 2 -#define MCS_MODE0 ((__u16)0x0001) -#define MCS_STFIR ((__u16)0x0002) -#define MCS_XCVR_CONF ((__u16)0x0004) -#define MCS_RXFAST ((__u16)0x0008) -/* TXCUR [6:4] */ -#define MCS_TXCUR_SHIFT 4 -#define MCS_TXCUR_MASK ((__u16)0x0070) -#define MCS_TXCUR(x) ((x & MCS_TXCUR_MASK) >> MCS_TXCUR_SHIFT) -#define MCS_SETTXCUR(x,y) \ - ((x & ~MCS_TXCUR_MASK) | (y << MCS_TXCUR_SHIFT) & MCS_TXCUR_MASK) - -#define MCS_MODE1 ((__u16)0x0080) -#define MCS_SMODE0 ((__u16)0x0100) -#define MCS_SMODE1 ((__u16)0x0200) -#define MCS_INVTX ((__u16)0x0400) -#define MCS_INVRX ((__u16)0x0800) - -#define MCS_MINRXPW_REG 4 - -#define MCS_RESV_REG 7 -#define MCS_IRINTX ((__u16)0x0001) -#define MCS_IRINRX ((__u16)0x0002) - -struct mcs_cb { - struct usb_device *usbdev; /* init: probe_irda */ - struct net_device *netdev; /* network layer */ - struct irlap_cb *irlap; /* The link layer we are binded to */ - struct qos_info qos; - unsigned int speed; /* Current speed */ - unsigned int new_speed; /* new speed */ - - struct work_struct work; /* Change speed work */ - - struct sk_buff *tx_pending; - char in_buf[4096]; /* transmit/receive buffer */ - char out_buf[4096]; /* transmit/receive buffer */ - __u8 *fifo_status; - - iobuff_t rx_buff; /* receive unwrap state machine */ - spinlock_t lock; - int receiving; - - __u8 ep_in; - __u8 ep_out; - - struct urb *rx_urb; - struct urb *tx_urb; - - int transceiver_type; - int sir_tweak; - int receive_mode; -}; - -static int mcs_set_reg(struct mcs_cb *mcs, __u16 reg, __u16 val); -static int mcs_get_reg(struct mcs_cb *mcs, __u16 reg, __u16 * val); - -static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs); -static inline int mcs_setup_transceiver_agilent(struct mcs_cb *mcs); -static inline int mcs_setup_transceiver_sharp(struct mcs_cb *mcs); -static inline int mcs_setup_transceiver(struct mcs_cb *mcs); -static inline int mcs_wrap_sir_skb(struct sk_buff *skb, __u8 * buf); -static unsigned mcs_wrap_fir_skb(const struct sk_buff *skb, __u8 *buf); -static unsigned mcs_wrap_mir_skb(const struct sk_buff *skb, __u8 *buf); -static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len); -static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len); -static inline int mcs_setup_urbs(struct mcs_cb *mcs); -static inline int mcs_receive_start(struct mcs_cb *mcs); -static inline int mcs_find_endpoints(struct mcs_cb *mcs, - struct usb_host_endpoint *ep, int epnum); - -static int mcs_speed_change(struct mcs_cb *mcs); - -static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd); -static int mcs_net_close(struct net_device *netdev); -static int mcs_net_open(struct net_device *netdev); - -static void mcs_receive_irq(struct urb *urb); -static void mcs_send_irq(struct urb *urb); -static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, - struct net_device *netdev); - -static int mcs_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void mcs_disconnect(struct usb_interface *intf); - -#endif /* _MCS7780_H */ diff --git a/drivers/staging/irda/drivers/nsc-ircc.c b/drivers/staging/irda/drivers/nsc-ircc.c deleted file mode 100644 index 7beae147be11..000000000000 --- a/drivers/staging/irda/drivers/nsc-ircc.c +++ /dev/null @@ -1,2410 +0,0 @@ -/********************************************************************* - * - * Filename: nsc-ircc.c - * Version: 1.0 - * Description: Driver for the NSC PC'108 and PC'338 IrDA chipsets - * Status: Stable. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Wed Mar 1 11:29:34 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com> - * Copyright (c) 1998 Actisys Corp., www.actisys.com - * Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.com> - * All Rights Reserved - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - * Notice that all functions that needs to access the chip in _any_ - * way, must save BSR register on entry, and restore it on exit. - * It is _very_ important to follow this policy! - * - * __u8 bank; - * - * bank = inb(iobase+BSR); - * - * do_your_stuff_here(); - * - * outb(bank, iobase+BSR); - * - * If you find bugs in this file, its very likely that the same bug - * will also be in w83977af_ir.c since the implementations are quite - * similar. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/gfp.h> - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/rtnetlink.h> -#include <linux/dma-mapping.h> -#include <linux/pnp.h> -#include <linux/platform_device.h> - -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/byteorder.h> - -#include <net/irda/wrapper.h> -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#include "nsc-ircc.h" - -#define CHIP_IO_EXTENT 8 -#define BROKEN_DONGLE_ID - -static char *driver_name = "nsc-ircc"; - -/* Power Management */ -#define NSC_IRCC_DRIVER_NAME "nsc-ircc" -static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state); -static int nsc_ircc_resume(struct platform_device *dev); - -static struct platform_driver nsc_ircc_driver = { - .suspend = nsc_ircc_suspend, - .resume = nsc_ircc_resume, - .driver = { - .name = NSC_IRCC_DRIVER_NAME, - }, -}; - -/* Module parameters */ -static int qos_mtt_bits = 0x07; /* 1 ms or more */ -static int dongle_id; - -/* Use BIOS settions by default, but user may supply module parameters */ -static unsigned int io[] = { ~0, ~0, ~0, ~0, ~0 }; -static unsigned int irq[] = { 0, 0, 0, 0, 0 }; -static unsigned int dma[] = { 0, 0, 0, 0, 0 }; - -static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); -static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); -static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info); -static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info); -static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info); -static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info); -#ifdef CONFIG_PNP -static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id); -#endif - -/* These are the known NSC chips */ -static nsc_chip_t chips[] = { -/* Name, {cfg registers}, chip id index reg, chip id expected value, revision mask */ - { "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, - nsc_ircc_probe_108, nsc_ircc_init_108 }, - { "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8, - nsc_ircc_probe_338, nsc_ircc_init_338 }, - /* Contributed by Steffen Pingel - IBM X40 */ - { "PC8738x", { 0x164e, 0x4e, 0x2e }, 0x20, 0xf4, 0xff, - nsc_ircc_probe_39x, nsc_ircc_init_39x }, - /* Contributed by Jan Frey - IBM A30/A31 */ - { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, - nsc_ircc_probe_39x, nsc_ircc_init_39x }, - /* IBM ThinkPads using PC8738x (T60/X60/Z60) */ - { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, - nsc_ircc_probe_39x, nsc_ircc_init_39x }, - /* IBM ThinkPads using PC8394T (T43/R52/?) */ - { "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff, - nsc_ircc_probe_39x, nsc_ircc_init_39x }, - { NULL } -}; - -static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL }; - -static char *dongle_types[] = { - "Differential serial interface", - "Differential serial interface", - "Reserved", - "Reserved", - "Sharp RY5HD01", - "Reserved", - "Single-ended serial interface", - "Consumer-IR only", - "HP HSDL-2300, HP HSDL-3600/HSDL-3610", - "IBM31T1100 or Temic TFDS6000/TFDS6500", - "Reserved", - "Reserved", - "HP HSDL-1100/HSDL-2100", - "HP HSDL-1100/HSDL-2100", - "Supports SIR Mode only", - "No dongle connected", -}; - -/* PNP probing */ -static chipio_t pnp_info; -static const struct pnp_device_id nsc_ircc_pnp_table[] = { - { .id = "NSC6001", .driver_data = 0 }, - { .id = "HWPC224", .driver_data = 0 }, - { .id = "IBM0071", .driver_data = NSC_FORCE_DONGLE_TYPE9 }, - { } -}; - -MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table); - -static struct pnp_driver nsc_ircc_pnp_driver = { -#ifdef CONFIG_PNP - .name = "nsc-ircc", - .id_table = nsc_ircc_pnp_table, - .probe = nsc_ircc_pnp_probe, -#endif -}; - -/* Some prototypes */ -static int nsc_ircc_open(chipio_t *info); -static int nsc_ircc_close(struct nsc_ircc_cb *self); -static int nsc_ircc_setup(chipio_t *info); -static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); -static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self); -static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase); -static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev); -static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev); -static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size); -static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase); -static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud); -static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self); -static int nsc_ircc_read_dongle_id (int iobase); -static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id); - -static int nsc_ircc_net_open(struct net_device *dev); -static int nsc_ircc_net_close(struct net_device *dev); -static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - -/* Globals */ -static int pnp_registered; -static int pnp_succeeded; - -/* - * Function nsc_ircc_init () - * - * Initialize chip. Just try to find out how many chips we are dealing with - * and where they are - */ -static int __init nsc_ircc_init(void) -{ - chipio_t info; - nsc_chip_t *chip; - int ret; - int cfg_base; - int cfg, id; - int reg; - int i = 0; - - ret = platform_driver_register(&nsc_ircc_driver); - if (ret) { - net_err_ratelimited("%s, Can't register driver!\n", - driver_name); - return ret; - } - - /* Register with PnP subsystem to detect disable ports */ - ret = pnp_register_driver(&nsc_ircc_pnp_driver); - - if (!ret) - pnp_registered = 1; - - ret = -ENODEV; - - /* Probe for all the NSC chipsets we know about */ - for (chip = chips; chip->name ; chip++) { - pr_debug("%s(), Probing for %s ...\n", __func__, - chip->name); - - /* Try all config registers for this chip */ - for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) { - cfg_base = chip->cfg[cfg]; - if (!cfg_base) - continue; - - /* Read index register */ - reg = inb(cfg_base); - if (reg == 0xff) { - pr_debug("%s() no chip at 0x%03x\n", - __func__, cfg_base); - continue; - } - - /* Read chip identification register */ - outb(chip->cid_index, cfg_base); - id = inb(cfg_base+1); - if ((id & chip->cid_mask) == chip->cid_value) { - pr_debug("%s() Found %s chip, revision=%d\n", - __func__, chip->name, - id & ~chip->cid_mask); - - /* - * If we found a correct PnP setting, - * we first try it. - */ - if (pnp_succeeded) { - memset(&info, 0, sizeof(chipio_t)); - info.cfg_base = cfg_base; - info.fir_base = pnp_info.fir_base; - info.dma = pnp_info.dma; - info.irq = pnp_info.irq; - - if (info.fir_base < 0x2000) { - net_info_ratelimited("%s, chip->init\n", - driver_name); - chip->init(chip, &info); - } else - chip->probe(chip, &info); - - if (nsc_ircc_open(&info) >= 0) - ret = 0; - } - - /* - * Opening based on PnP values failed. - * Let's fallback to user values, or probe - * the chip. - */ - if (ret) { - pr_debug("%s, PnP init failed\n", - driver_name); - memset(&info, 0, sizeof(chipio_t)); - info.cfg_base = cfg_base; - info.fir_base = io[i]; - info.dma = dma[i]; - info.irq = irq[i]; - - /* - * If the user supplies the base address, then - * we init the chip, if not we probe the values - * set by the BIOS - */ - if (io[i] < 0x2000) { - chip->init(chip, &info); - } else - chip->probe(chip, &info); - - if (nsc_ircc_open(&info) >= 0) - ret = 0; - } - i++; - } else { - pr_debug("%s(), Wrong chip id=0x%02x\n", - __func__, id); - } - } - } - - if (ret) { - platform_driver_unregister(&nsc_ircc_driver); - pnp_unregister_driver(&nsc_ircc_pnp_driver); - pnp_registered = 0; - } - - return ret; -} - -/* - * Function nsc_ircc_cleanup () - * - * Close all configured chips - * - */ -static void __exit nsc_ircc_cleanup(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dev_self); i++) { - if (dev_self[i]) - nsc_ircc_close(dev_self[i]); - } - - platform_driver_unregister(&nsc_ircc_driver); - - if (pnp_registered) - pnp_unregister_driver(&nsc_ircc_pnp_driver); - - pnp_registered = 0; -} - -static const struct net_device_ops nsc_ircc_sir_ops = { - .ndo_open = nsc_ircc_net_open, - .ndo_stop = nsc_ircc_net_close, - .ndo_start_xmit = nsc_ircc_hard_xmit_sir, - .ndo_do_ioctl = nsc_ircc_net_ioctl, -}; - -static const struct net_device_ops nsc_ircc_fir_ops = { - .ndo_open = nsc_ircc_net_open, - .ndo_stop = nsc_ircc_net_close, - .ndo_start_xmit = nsc_ircc_hard_xmit_fir, - .ndo_do_ioctl = nsc_ircc_net_ioctl, -}; - -/* - * Function nsc_ircc_open (iobase, irq) - * - * Open driver instance - * - */ -static int __init nsc_ircc_open(chipio_t *info) -{ - struct net_device *dev; - struct nsc_ircc_cb *self; - void *ret; - int err, chip_index; - - for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) { - if (!dev_self[chip_index]) - break; - } - - if (chip_index == ARRAY_SIZE(dev_self)) { - net_err_ratelimited("%s(), maximum number of supported chips reached!\n", - __func__); - return -ENOMEM; - } - - net_info_ratelimited("%s, Found chip at base=0x%03x\n", - driver_name, info->cfg_base); - - if ((nsc_ircc_setup(info)) == -1) - return -1; - - net_info_ratelimited("%s, driver loaded (Dag Brattli)\n", driver_name); - - dev = alloc_irdadev(sizeof(struct nsc_ircc_cb)); - if (dev == NULL) { - net_err_ratelimited("%s(), can't allocate memory for control block!\n", - __func__); - return -ENOMEM; - } - - self = netdev_priv(dev); - self->netdev = dev; - spin_lock_init(&self->lock); - - /* Need to store self somewhere */ - dev_self[chip_index] = self; - self->index = chip_index; - - /* Initialize IO */ - self->io.cfg_base = info->cfg_base; - self->io.fir_base = info->fir_base; - self->io.irq = info->irq; - self->io.fir_ext = CHIP_IO_EXTENT; - self->io.dma = info->dma; - self->io.fifo_size = 32; - - /* Reserve the ioports that we need */ - ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name); - if (!ret) { - net_warn_ratelimited("%s(), can't get iobase of 0x%03x\n", - __func__, self->io.fir_base); - err = -ENODEV; - goto out1; - } - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - /* The only value we must override it the baudrate */ - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8); - - self->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&self->qos); - - /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ - self->rx_buff.truesize = 14384; - self->tx_buff.truesize = 14384; - - /* Allocate memory if needed */ - self->rx_buff.head = - dma_zalloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL); - if (self->rx_buff.head == NULL) { - err = -ENOMEM; - goto out2; - - } - - self->tx_buff.head = - dma_zalloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL); - if (self->tx_buff.head == NULL) { - err = -ENOMEM; - goto out3; - } - - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Tx queue info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - - /* Override the network functions we need to use */ - dev->netdev_ops = &nsc_ircc_sir_ops; - - err = register_netdev(dev); - if (err) { - net_err_ratelimited("%s(), register_netdev() failed!\n", - __func__); - goto out4; - } - net_info_ratelimited("IrDA: Registered device %s\n", dev->name); - - /* Check if user has supplied a valid dongle id or not */ - if ((dongle_id <= 0) || - (dongle_id >= ARRAY_SIZE(dongle_types))) { - dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); - - net_info_ratelimited("%s, Found dongle: %s\n", - driver_name, dongle_types[dongle_id]); - } else { - net_info_ratelimited("%s, Using dongle: %s\n", - driver_name, dongle_types[dongle_id]); - } - - self->io.dongle_id = dongle_id; - nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); - - self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME, - self->index, NULL, 0); - if (IS_ERR(self->pldev)) { - err = PTR_ERR(self->pldev); - goto out5; - } - platform_set_drvdata(self->pldev, self); - - return chip_index; - - out5: - unregister_netdev(dev); - out4: - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - out3: - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - out2: - release_region(self->io.fir_base, self->io.fir_ext); - out1: - free_netdev(dev); - dev_self[chip_index] = NULL; - return err; -} - -/* - * Function nsc_ircc_close (self) - * - * Close driver instance - * - */ -static int __exit nsc_ircc_close(struct nsc_ircc_cb *self) -{ - int iobase; - - IRDA_ASSERT(self != NULL, return -1;); - - iobase = self->io.fir_base; - - platform_device_unregister(self->pldev); - - /* Remove netdevice */ - unregister_netdev(self->netdev); - - /* Release the PORT that this driver is using */ - pr_debug("%s(), Releasing Region %03x\n", - __func__, self->io.fir_base); - release_region(self->io.fir_base, self->io.fir_ext); - - if (self->tx_buff.head) - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - - if (self->rx_buff.head) - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - - dev_self[self->index] = NULL; - free_netdev(self->netdev); - - return 0; -} - -/* - * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma) - * - * Initialize the NSC '108 chip - * - */ -static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info) -{ - int cfg_base = info->cfg_base; - __u8 temp=0; - - outb(2, cfg_base); /* Mode Control Register (MCTL) */ - outb(0x00, cfg_base+1); /* Disable device */ - - /* Base Address and Interrupt Control Register (BAIC) */ - outb(CFG_108_BAIC, cfg_base); - switch (info->fir_base) { - case 0x3e8: outb(0x14, cfg_base+1); break; - case 0x2e8: outb(0x15, cfg_base+1); break; - case 0x3f8: outb(0x16, cfg_base+1); break; - case 0x2f8: outb(0x17, cfg_base+1); break; - default: net_err_ratelimited("%s(), invalid base_address\n", __func__); - } - - /* Control Signal Routing Register (CSRT) */ - switch (info->irq) { - case 3: temp = 0x01; break; - case 4: temp = 0x02; break; - case 5: temp = 0x03; break; - case 7: temp = 0x04; break; - case 9: temp = 0x05; break; - case 11: temp = 0x06; break; - case 15: temp = 0x07; break; - default: net_err_ratelimited("%s(), invalid irq\n", __func__); - } - outb(CFG_108_CSRT, cfg_base); - - switch (info->dma) { - case 0: outb(0x08+temp, cfg_base+1); break; - case 1: outb(0x10+temp, cfg_base+1); break; - case 3: outb(0x18+temp, cfg_base+1); break; - default: net_err_ratelimited("%s(), invalid dma\n", __func__); - } - - outb(CFG_108_MCTL, cfg_base); /* Mode Control Register (MCTL) */ - outb(0x03, cfg_base+1); /* Enable device */ - - return 0; -} - -/* - * Function nsc_ircc_probe_108 (chip, info) - * - * - * - */ -static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) -{ - int cfg_base = info->cfg_base; - int reg; - - /* Read address and interrupt control register (BAIC) */ - outb(CFG_108_BAIC, cfg_base); - reg = inb(cfg_base+1); - - switch (reg & 0x03) { - case 0: - info->fir_base = 0x3e8; - break; - case 1: - info->fir_base = 0x2e8; - break; - case 2: - info->fir_base = 0x3f8; - break; - case 3: - info->fir_base = 0x2f8; - break; - } - info->sir_base = info->fir_base; - pr_debug("%s(), probing fir_base=0x%03x\n", __func__, - info->fir_base); - - /* Read control signals routing register (CSRT) */ - outb(CFG_108_CSRT, cfg_base); - reg = inb(cfg_base+1); - - switch (reg & 0x07) { - case 0: - info->irq = -1; - break; - case 1: - info->irq = 3; - break; - case 2: - info->irq = 4; - break; - case 3: - info->irq = 5; - break; - case 4: - info->irq = 7; - break; - case 5: - info->irq = 9; - break; - case 6: - info->irq = 11; - break; - case 7: - info->irq = 15; - break; - } - pr_debug("%s(), probing irq=%d\n", __func__, info->irq); - - /* Currently we only read Rx DMA but it will also be used for Tx */ - switch ((reg >> 3) & 0x03) { - case 0: - info->dma = -1; - break; - case 1: - info->dma = 0; - break; - case 2: - info->dma = 1; - break; - case 3: - info->dma = 3; - break; - } - pr_debug("%s(), probing dma=%d\n", __func__, info->dma); - - /* Read mode control register (MCTL) */ - outb(CFG_108_MCTL, cfg_base); - reg = inb(cfg_base+1); - - info->enabled = reg & 0x01; - info->suspended = !((reg >> 1) & 0x01); - - return 0; -} - -/* - * Function nsc_ircc_init_338 (chip, info) - * - * Initialize the NSC '338 chip. Remember that the 87338 needs two - * consecutive writes to the data registers while CPU interrupts are - * disabled. The 97338 does not require this, but shouldn't be any - * harm if we do it anyway. - */ -static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info) -{ - /* No init yet */ - - return 0; -} - -/* - * Function nsc_ircc_probe_338 (chip, info) - * - * - * - */ -static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) -{ - int cfg_base = info->cfg_base; - int reg, com = 0; - int pnp; - - /* Read function enable register (FER) */ - outb(CFG_338_FER, cfg_base); - reg = inb(cfg_base+1); - - info->enabled = (reg >> 2) & 0x01; - - /* Check if we are in Legacy or PnP mode */ - outb(CFG_338_PNP0, cfg_base); - reg = inb(cfg_base+1); - - pnp = (reg >> 3) & 0x01; - if (pnp) { - pr_debug("(), Chip is in PnP mode\n"); - outb(0x46, cfg_base); - reg = (inb(cfg_base+1) & 0xfe) << 2; - - outb(0x47, cfg_base); - reg |= ((inb(cfg_base+1) & 0xfc) << 8); - - info->fir_base = reg; - } else { - /* Read function address register (FAR) */ - outb(CFG_338_FAR, cfg_base); - reg = inb(cfg_base+1); - - switch ((reg >> 4) & 0x03) { - case 0: - info->fir_base = 0x3f8; - break; - case 1: - info->fir_base = 0x2f8; - break; - case 2: - com = 3; - break; - case 3: - com = 4; - break; - } - - if (com) { - switch ((reg >> 6) & 0x03) { - case 0: - if (com == 3) - info->fir_base = 0x3e8; - else - info->fir_base = 0x2e8; - break; - case 1: - if (com == 3) - info->fir_base = 0x338; - else - info->fir_base = 0x238; - break; - case 2: - if (com == 3) - info->fir_base = 0x2e8; - else - info->fir_base = 0x2e0; - break; - case 3: - if (com == 3) - info->fir_base = 0x220; - else - info->fir_base = 0x228; - break; - } - } - } - info->sir_base = info->fir_base; - - /* Read PnP register 1 (PNP1) */ - outb(CFG_338_PNP1, cfg_base); - reg = inb(cfg_base+1); - - info->irq = reg >> 4; - - /* Read PnP register 3 (PNP3) */ - outb(CFG_338_PNP3, cfg_base); - reg = inb(cfg_base+1); - - info->dma = (reg & 0x07) - 1; - - /* Read power and test register (PTR) */ - outb(CFG_338_PTR, cfg_base); - reg = inb(cfg_base+1); - - info->suspended = reg & 0x01; - - return 0; -} - - -/* - * Function nsc_ircc_init_39x (chip, info) - * - * Now that we know it's a '39x (see probe below), we need to - * configure it so we can use it. - * - * The NSC '338 chip is a Super I/O chip with a "bank" architecture, - * the configuration of the different functionality (serial, parallel, - * floppy...) are each in a different bank (Logical Device Number). - * The base address, irq and dma configuration registers are common - * to all functionalities (index 0x30 to 0x7F). - * There is only one configuration register specific to the - * serial port, CFG_39X_SPC. - * JeanII - * - * Note : this code was written by Jan Frey <janfrey@web.de> - */ -static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info) -{ - int cfg_base = info->cfg_base; - int enabled; - - /* User is sure about his config... accept it. */ - pr_debug("%s(): nsc_ircc_init_39x (user settings): io=0x%04x, irq=%d, dma=%d\n", - __func__, info->fir_base, info->irq, info->dma); - - /* Access bank for SP2 */ - outb(CFG_39X_LDN, cfg_base); - outb(0x02, cfg_base+1); - - /* Configure SP2 */ - - /* We want to enable the device if not enabled */ - outb(CFG_39X_ACT, cfg_base); - enabled = inb(cfg_base+1) & 0x01; - - if (!enabled) { - /* Enable the device */ - outb(CFG_39X_SIOCF1, cfg_base); - outb(0x01, cfg_base+1); - /* May want to update info->enabled. Jean II */ - } - - /* Enable UART bank switching (bit 7) ; Sets the chip to normal - * power mode (wake up from sleep mode) (bit 1) */ - outb(CFG_39X_SPC, cfg_base); - outb(0x82, cfg_base+1); - - return 0; -} - -/* - * Function nsc_ircc_probe_39x (chip, info) - * - * Test if we really have a '39x chip at the given address - * - * Note : this code was written by Jan Frey <janfrey@web.de> - */ -static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info) -{ - int cfg_base = info->cfg_base; - int reg1, reg2, irq, irqt, dma1, dma2; - int enabled, susp; - - pr_debug("%s(), nsc_ircc_probe_39x, base=%d\n", - __func__, cfg_base); - - /* This function should be executed with irq off to avoid - * another driver messing with the Super I/O bank - Jean II */ - - /* Access bank for SP2 */ - outb(CFG_39X_LDN, cfg_base); - outb(0x02, cfg_base+1); - - /* Read infos about SP2 ; store in info struct */ - outb(CFG_39X_BASEH, cfg_base); - reg1 = inb(cfg_base+1); - outb(CFG_39X_BASEL, cfg_base); - reg2 = inb(cfg_base+1); - info->fir_base = (reg1 << 8) | reg2; - - outb(CFG_39X_IRQNUM, cfg_base); - irq = inb(cfg_base+1); - outb(CFG_39X_IRQSEL, cfg_base); - irqt = inb(cfg_base+1); - info->irq = irq; - - outb(CFG_39X_DMA0, cfg_base); - dma1 = inb(cfg_base+1); - outb(CFG_39X_DMA1, cfg_base); - dma2 = inb(cfg_base+1); - info->dma = dma1 -1; - - outb(CFG_39X_ACT, cfg_base); - info->enabled = enabled = inb(cfg_base+1) & 0x01; - - outb(CFG_39X_SPC, cfg_base); - susp = 1 - ((inb(cfg_base+1) & 0x02) >> 1); - - pr_debug("%s(): io=0x%02x%02x, irq=%d (type %d), rxdma=%d, txdma=%d, enabled=%d (suspended=%d)\n", - __func__, reg1, reg2, irq, irqt, dma1, dma2, enabled, susp); - - /* Configure SP2 */ - - /* We want to enable the device if not enabled */ - outb(CFG_39X_ACT, cfg_base); - enabled = inb(cfg_base+1) & 0x01; - - if (!enabled) { - /* Enable the device */ - outb(CFG_39X_SIOCF1, cfg_base); - outb(0x01, cfg_base+1); - /* May want to update info->enabled. Jean II */ - } - - /* Enable UART bank switching (bit 7) ; Sets the chip to normal - * power mode (wake up from sleep mode) (bit 1) */ - outb(CFG_39X_SPC, cfg_base); - outb(0x82, cfg_base+1); - - return 0; -} - -#ifdef CONFIG_PNP -/* PNP probing */ -static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id) -{ - memset(&pnp_info, 0, sizeof(chipio_t)); - pnp_info.irq = -1; - pnp_info.dma = -1; - pnp_succeeded = 1; - - if (id->driver_data & NSC_FORCE_DONGLE_TYPE9) - dongle_id = 0x9; - - /* There doesn't seem to be any way of getting the cfg_base. - * On my box, cfg_base is in the PnP descriptor of the - * motherboard. Oh well... Jean II */ - - if (pnp_port_valid(dev, 0) && - !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) - pnp_info.fir_base = pnp_port_start(dev, 0); - - if (pnp_irq_valid(dev, 0) && - !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) - pnp_info.irq = pnp_irq(dev, 0); - - if (pnp_dma_valid(dev, 0) && - !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) - pnp_info.dma = pnp_dma(dev, 0); - - pr_debug("%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n", - __func__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma); - - if((pnp_info.fir_base == 0) || - (pnp_info.irq == -1) || (pnp_info.dma == -1)) { - /* Returning an error will disable the device. Yuck ! */ - //return -EINVAL; - pnp_succeeded = 0; - } - - return 0; -} -#endif - -/* - * Function nsc_ircc_setup (info) - * - * Returns non-negative on success. - * - */ -static int nsc_ircc_setup(chipio_t *info) -{ - int version; - int iobase = info->fir_base; - - /* Read the Module ID */ - switch_bank(iobase, BANK3); - version = inb(iobase+MID); - - pr_debug("%s() Driver %s Found chip version %02x\n", - __func__, driver_name, version); - - /* Should be 0x2? */ - if (0x20 != (version & 0xf0)) { - net_err_ratelimited("%s, Wrong chip version %02x\n", - driver_name, version); - return -1; - } - - /* Switch to advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_EXT_SL, iobase+ECR1); - switch_bank(iobase, BANK0); - - /* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */ - switch_bank(iobase, BANK0); - outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); - - outb(0x03, iobase+LCR); /* 8 bit word length */ - outb(MCR_SIR, iobase+MCR); /* Start at SIR-mode, also clears LSR*/ - - /* Set FIFO size to 32 */ - switch_bank(iobase, BANK2); - outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); - - /* IRCR2: FEND_MD is not set */ - switch_bank(iobase, BANK5); - outb(0x02, iobase+4); - - /* Make sure that some defaults are OK */ - switch_bank(iobase, BANK6); - outb(0x20, iobase+0); /* Set 32 bits FIR CRC */ - outb(0x0a, iobase+1); /* Set MIR pulse width */ - outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */ - outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */ - - /* Enable receive interrupts */ - switch_bank(iobase, BANK0); - outb(IER_RXHDL_IE, iobase+IER); - - return 0; -} - -/* - * Function nsc_ircc_read_dongle_id (void) - * - * Try to read dongle identification. This procedure needs to be executed - * once after power-on/reset. It also needs to be used whenever you suspect - * that the user may have plugged/unplugged the IrDA Dongle. - */ -static int nsc_ircc_read_dongle_id (int iobase) -{ - int dongle_id; - __u8 bank; - - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */ - outb(0x00, iobase+7); - - /* ID0, 1, and 2 are pulled up/down very slowly */ - udelay(50); - - /* IRCFG1: read the ID bits */ - dongle_id = inb(iobase+4) & 0x0f; - -#ifdef BROKEN_DONGLE_ID - if (dongle_id == 0x0a) - dongle_id = 0x09; -#endif - /* Go back to bank 0 before returning */ - switch_bank(iobase, BANK0); - - outb(bank, iobase+BSR); - - return dongle_id; -} - -/* - * Function nsc_ircc_init_dongle_interface (iobase, dongle_id) - * - * This function initializes the dongle for the transceiver that is - * used. This procedure needs to be executed once after - * power-on/reset. It also needs to be used whenever you suspect that - * the dongle is changed. - */ -static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id) -{ - int bank; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG4: set according to dongle_id */ - switch (dongle_id) { - case 0x00: /* same as */ - case 0x01: /* Differential serial interface */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x02: /* same as */ - case 0x03: /* Reserved */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x04: /* Sharp RY5HD01 */ - break; - case 0x05: /* Reserved, but this is what the Thinkpad reports */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x06: /* Single-ended serial interface */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x07: /* Consumer-IR only */ - pr_debug("%s(), %s is not for IrDA mode\n", - __func__, dongle_types[dongle_id]); - break; - case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - pr_debug("%s(), %s\n", - __func__, dongle_types[dongle_id]); - break; - case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - outb(0x28, iobase+7); /* Set irsl[0-2] as output */ - break; - case 0x0A: /* same as */ - case 0x0B: /* Reserved */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x0C: /* same as */ - case 0x0D: /* HP HSDL-1100/HSDL-2100 */ - /* - * Set irsl0 as input, irsl[1-2] as output, and separate - * inputs are used for SIR and MIR/FIR - */ - outb(0x48, iobase+7); - break; - case 0x0E: /* Supports SIR Mode only */ - outb(0x28, iobase+7); /* Set irsl[0-2] as output */ - break; - case 0x0F: /* No dongle connected */ - pr_debug("%s(), %s\n", - __func__, dongle_types[dongle_id]); - - switch_bank(iobase, BANK0); - outb(0x62, iobase+MCR); - break; - default: - pr_debug("%s(), invalid dongle_id %#x", - __func__, dongle_id); - } - - /* IRCFG1: IRSL1 and 2 are set to IrDA mode */ - outb(0x00, iobase+4); - - /* Restore bank register */ - outb(bank, iobase+BSR); - -} /* set_up_dongle_interface */ - -/* - * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id) - * - * Change speed of the attach dongle - * - */ -static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id) -{ - __u8 bank; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Select Bank 7 */ - switch_bank(iobase, BANK7); - - /* IRCFG1: set according to dongle_id */ - switch (dongle_id) { - case 0x00: /* same as */ - case 0x01: /* Differential serial interface */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x02: /* same as */ - case 0x03: /* Reserved */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x04: /* Sharp RY5HD01 */ - break; - case 0x05: /* Reserved */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x06: /* Single-ended serial interface */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x07: /* Consumer-IR only */ - pr_debug("%s(), %s is not for IrDA mode\n", - __func__, dongle_types[dongle_id]); - break; - case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - pr_debug("%s(), %s\n", - __func__, dongle_types[dongle_id]); - outb(0x00, iobase+4); - if (speed > 115200) - outb(0x01, iobase+4); - break; - case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - outb(0x01, iobase+4); - - if (speed == 4000000) { - /* There was a cli() there, but we now are already - * under spin_lock_irqsave() - JeanII */ - outb(0x81, iobase+4); - outb(0x80, iobase+4); - } else - outb(0x00, iobase+4); - break; - case 0x0A: /* same as */ - case 0x0B: /* Reserved */ - pr_debug("%s(), %s not defined by irda yet\n", - __func__, dongle_types[dongle_id]); - break; - case 0x0C: /* same as */ - case 0x0D: /* HP HSDL-1100/HSDL-2100 */ - break; - case 0x0E: /* Supports SIR Mode only */ - break; - case 0x0F: /* No dongle connected */ - pr_debug("%s(), %s is not for IrDA mode\n", - __func__, dongle_types[dongle_id]); - - switch_bank(iobase, BANK0); - outb(0x62, iobase+MCR); - break; - default: - pr_debug("%s(), invalid data_rate\n", __func__); - } - /* Restore bank register */ - outb(bank, iobase+BSR); -} - -/* - * Function nsc_ircc_change_speed (self, baud) - * - * Change the speed of the device - * - * This function *must* be called with irq off and spin-lock. - */ -static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed) -{ - struct net_device *dev; - __u8 mcr = MCR_SIR; - int iobase; - __u8 bank; - __u8 ier; /* Interrupt enable register */ - - pr_debug("%s(), speed=%d\n", __func__, speed); - - IRDA_ASSERT(self != NULL, return 0;); - - dev = self->netdev; - iobase = self->io.fir_base; - - /* Update accounting for new speed */ - self->io.speed = speed; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable interrupts */ - switch_bank(iobase, BANK0); - outb(0, iobase+IER); - - /* Select Bank 2 */ - switch_bank(iobase, BANK2); - - outb(0x00, iobase+BGDH); - switch (speed) { - case 9600: outb(0x0c, iobase+BGDL); break; - case 19200: outb(0x06, iobase+BGDL); break; - case 38400: outb(0x03, iobase+BGDL); break; - case 57600: outb(0x02, iobase+BGDL); break; - case 115200: outb(0x01, iobase+BGDL); break; - case 576000: - switch_bank(iobase, BANK5); - - /* IRCR2: MDRS is set */ - outb(inb(iobase+4) | 0x04, iobase+4); - - mcr = MCR_MIR; - pr_debug("%s(), handling baud of 576000\n", __func__); - break; - case 1152000: - mcr = MCR_MIR; - pr_debug("%s(), handling baud of 1152000\n", __func__); - break; - case 4000000: - mcr = MCR_FIR; - pr_debug("%s(), handling baud of 4000000\n", __func__); - break; - default: - mcr = MCR_FIR; - pr_debug("%s(), unknown baud rate of %d\n", - __func__, speed); - break; - } - - /* Set appropriate speed mode */ - switch_bank(iobase, BANK0); - outb(mcr | MCR_TX_DFR, iobase+MCR); - - /* Give some hits to the transceiver */ - nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id); - - /* Set FIFO threshold to TX17, RX16 */ - switch_bank(iobase, BANK0); - outb(0x00, iobase+FCR); - outb(FCR_FIFO_EN, iobase+FCR); - outb(FCR_RXTH| /* Set Rx FIFO threshold */ - FCR_TXTH| /* Set Tx FIFO threshold */ - FCR_TXSR| /* Reset Tx FIFO */ - FCR_RXSR| /* Reset Rx FIFO */ - FCR_FIFO_EN, /* Enable FIFOs */ - iobase+FCR); - - /* Set FIFO size to 32 */ - switch_bank(iobase, BANK2); - outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2); - - /* Enable some interrupts so we can receive frames */ - switch_bank(iobase, BANK0); - if (speed > 115200) { - /* Install FIR xmit handler */ - dev->netdev_ops = &nsc_ircc_fir_ops; - ier = IER_SFIF_IE; - nsc_ircc_dma_receive(self); - } else { - /* Install SIR xmit handler */ - dev->netdev_ops = &nsc_ircc_sir_ops; - ier = IER_RXHDL_IE; - } - /* Set our current interrupt mask */ - outb(ier, iobase+IER); - - /* Restore BSR */ - outb(bank, iobase+BSR); - - /* Make sure interrupt handlers keep the proper interrupt mask */ - return ier; -} - -/* - * Function nsc_ircc_hard_xmit (skb, dev) - * - * Transmit the frame! - * - */ -static netdev_tx_t nsc_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev) -{ - struct nsc_ircc_cb *self; - unsigned long flags; - int iobase; - __s32 speed; - __u8 bank; - - self = netdev_priv(dev); - - IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); - - iobase = self->io.fir_base; - - netif_stop_queue(dev); - - /* Make sure tests *& speed change are atomic */ - spin_lock_irqsave(&self->lock, flags); - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - /* Check for empty frame. */ - if (!skb->len) { - /* If we just sent a frame, we get called before - * the last bytes get out (because of the SIR FIFO). - * If this is the case, let interrupt handler change - * the speed itself... Jean II */ - if (self->io.direction == IO_RECV) { - nsc_ircc_change_speed(self, speed); - /* TODO : For SIR->SIR, the next packet - * may get corrupted - Jean II */ - netif_wake_queue(dev); - } else { - self->new_speed = speed; - /* Queue will be restarted after speed change - * to make sure packets gets through the - * proper xmit handler - Jean II */ - } - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else - self->new_speed = speed; - } - - /* Save current bank */ - bank = inb(iobase+BSR); - - self->tx_buff.data = self->tx_buff.head; - - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - dev->stats.tx_bytes += self->tx_buff.len; - - /* Add interrupt on tx low level (will fire immediately) */ - switch_bank(iobase, BANK0); - outb(IER_TXLDL_IE, iobase+IER); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev) -{ - struct nsc_ircc_cb *self; - unsigned long flags; - int iobase; - __s32 speed; - __u8 bank; - int mtt, diff; - - self = netdev_priv(dev); - iobase = self->io.fir_base; - - netif_stop_queue(dev); - - /* Make sure tests *& speed change are atomic */ - spin_lock_irqsave(&self->lock, flags); - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - /* Check for empty frame. */ - if (!skb->len) { - /* If we are currently transmitting, defer to - * interrupt handler. - Jean II */ - if(self->tx_fifo.len == 0) { - nsc_ircc_change_speed(self, speed); - netif_wake_queue(dev); - } else { - self->new_speed = speed; - /* Keep queue stopped : - * the speed change operation may change the - * xmit handler, and we want to make sure - * the next packet get through the proper - * Tx path, so block the Tx queue until - * the speed change has been done. - * Jean II */ - } - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else { - /* Change speed after current frame */ - self->new_speed = speed; - } - } - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Register and copy this frame to DMA memory */ - self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; - self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; - self->tx_fifo.tail += skb->len; - - dev->stats.tx_bytes += skb->len; - - skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, - skb->len); - self->tx_fifo.len++; - self->tx_fifo.free++; - - /* Start transmit only if there is currently no transmit going on */ - if (self->tx_fifo.len == 1) { - /* Check if we must wait the min turn time or not */ - mtt = irda_get_mtt(skb); - if (mtt) { - /* Check how much time we have used already */ - diff = ktime_us_delta(ktime_get(), self->stamp); - - /* Check if the mtt is larger than the time we have - * already used by all the protocol processing - */ - if (mtt > diff) { - mtt -= diff; - - /* - * Use timer if delay larger than 125 us, and - * use udelay for smaller values which should - * be acceptable - */ - if (mtt > 125) { - /* Adjust for timer resolution */ - mtt = mtt / 125; - - /* Setup timer */ - switch_bank(iobase, BANK4); - outb(mtt & 0xff, iobase+TMRL); - outb((mtt >> 8) & 0x0f, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - self->io.direction = IO_XMIT; - - /* Enable timer interrupt */ - switch_bank(iobase, BANK0); - outb(IER_TMR_IE, iobase+IER); - - /* Timer will take care of the rest */ - goto out; - } else - udelay(mtt); - } - } - /* Enable DMA interrupt */ - switch_bank(iobase, BANK0); - outb(IER_DMA_IE, iobase+IER); - - /* Transmit frame */ - nsc_ircc_dma_xmit(self, iobase); - } - out: - /* Not busy transmitting anymore if window is not full, - * and if we don't need to change speed */ - if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0)) - netif_wake_queue(self->netdev); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -/* - * Function nsc_ircc_dma_xmit (self, iobase) - * - * Transmit data using DMA - * - */ -static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase) -{ - int bsr; - - /* Save current bank */ - bsr = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - self->io.direction = IO_XMIT; - - /* Choose transmit DMA channel */ - switch_bank(iobase, BANK2); - outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); - - irda_setup_dma(self->io.dma, - ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start - - self->tx_buff.head) + self->tx_buff_dma, - self->tx_fifo.queue[self->tx_fifo.ptr].len, - DMA_TX_MODE); - - /* Enable DMA and SIR interaction pulse */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR); - - /* Restore bank register */ - outb(bsr, iobase+BSR); -} - -/* - * Function nsc_ircc_pio_xmit (self, iobase) - * - * Transmit data using PIO. Returns the number of bytes that actually - * got transferred - * - */ -static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size) -{ - int actual = 0; - __u8 bank; - - /* Save current bank */ - bank = inb(iobase+BSR); - - switch_bank(iobase, BANK0); - if (!(inb_p(iobase+LSR) & LSR_TXEMP)) { - pr_debug("%s(), warning, FIFO not empty yet!\n", - __func__); - - /* FIFO may still be filled to the Tx interrupt threshold */ - fifo_size -= 17; - } - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual++], iobase+TXD); - } - - pr_debug("%s(), fifo_size %d ; %d sent of %d\n", - __func__, fifo_size, actual, len); - - /* Restore bank */ - outb(bank, iobase+BSR); - - return actual; -} - -/* - * Function nsc_ircc_dma_xmit_complete (self) - * - * The transfer of a frame in finished. This function will only be called - * by the interrupt handler - * - */ -static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self) -{ - int iobase; - __u8 bank; - int ret = TRUE; - - iobase = self->io.fir_base; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - /* Check for underrun! */ - if (inb(iobase+ASCR) & ASCR_TXUR) { - self->netdev->stats.tx_errors++; - self->netdev->stats.tx_fifo_errors++; - - /* Clear bit, by writing 1 into it */ - outb(ASCR_TXUR, iobase+ASCR); - } else { - self->netdev->stats.tx_packets++; - } - - /* Finished with this frame, so prepare for next */ - self->tx_fifo.ptr++; - self->tx_fifo.len--; - - /* Any frames to be sent back-to-back? */ - if (self->tx_fifo.len) { - nsc_ircc_dma_xmit(self, iobase); - - /* Not finished yet! */ - ret = FALSE; - } else { - /* Reset Tx FIFO info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - } - - /* Make sure we have room for more frames and - * that we don't need to change speed */ - if ((self->tx_fifo.free < MAX_TX_WINDOW) && (self->new_speed == 0)) { - /* Not busy transmitting anymore */ - /* Tell the network layer, that we can accept more frames */ - netif_wake_queue(self->netdev); - } - - /* Restore bank */ - outb(bank, iobase+BSR); - - return ret; -} - -/* - * Function nsc_ircc_dma_receive (self) - * - * Get ready for receiving a frame. The device will initiate a DMA - * if it starts to receive a frame. - * - */ -static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self) -{ - int iobase; - __u8 bsr; - - iobase = self->io.fir_base; - - /* Reset Tx FIFO info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - - /* Save current bank */ - bsr = inb(iobase+BSR); - - /* Disable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR); - - /* Choose DMA Rx, DMA Fairness, and Advanced mode */ - switch_bank(iobase, BANK2); - outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1); - - self->io.direction = IO_RECV; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Rx FIFO. This will also flush the ST_FIFO */ - switch_bank(iobase, BANK0); - outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR); - - self->st_fifo.len = self->st_fifo.pending_bytes = 0; - self->st_fifo.tail = self->st_fifo.head = 0; - - irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, - DMA_RX_MODE); - - /* Enable DMA */ - switch_bank(iobase, BANK0); - outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR); - - /* Restore bank register */ - outb(bsr, iobase+BSR); - - return 0; -} - -/* - * Function nsc_ircc_dma_receive_complete (self) - * - * Finished with receiving frames - * - * - */ -static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) -{ - struct st_fifo *st_fifo; - struct sk_buff *skb; - __u8 status; - __u8 bank; - int len; - - st_fifo = &self->st_fifo; - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Read all entries in status FIFO */ - switch_bank(iobase, BANK5); - while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) { - /* We must empty the status FIFO no matter what */ - len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8); - - if (st_fifo->tail >= MAX_RX_WINDOW) { - pr_debug("%s(), window is full!\n", __func__); - continue; - } - - st_fifo->entries[st_fifo->tail].status = status; - st_fifo->entries[st_fifo->tail].len = len; - st_fifo->pending_bytes += len; - st_fifo->tail++; - st_fifo->len++; - } - /* Try to process all entries in status FIFO */ - while (st_fifo->len > 0) { - /* Get first entry */ - status = st_fifo->entries[st_fifo->head].status; - len = st_fifo->entries[st_fifo->head].len; - st_fifo->pending_bytes -= len; - st_fifo->head++; - st_fifo->len--; - - /* Check for errors */ - if (status & FRM_ST_ERR_MSK) { - if (status & FRM_ST_LOST_FR) { - /* Add number of lost frames to stats */ - self->netdev->stats.rx_errors += len; - } else { - /* Skip frame */ - self->netdev->stats.rx_errors++; - - self->rx_buff.data += len; - - if (status & FRM_ST_MAX_LEN) - self->netdev->stats.rx_length_errors++; - - if (status & FRM_ST_PHY_ERR) - self->netdev->stats.rx_frame_errors++; - - if (status & FRM_ST_BAD_CRC) - self->netdev->stats.rx_crc_errors++; - } - /* The errors below can be reported in both cases */ - if (status & FRM_ST_OVR1) - self->netdev->stats.rx_fifo_errors++; - - if (status & FRM_ST_OVR2) - self->netdev->stats.rx_fifo_errors++; - } else { - /* - * First we must make sure that the frame we - * want to deliver is all in main memory. If we - * cannot tell, then we check if the Rx FIFO is - * empty. If not then we will have to take a nap - * and try again later. - */ - if (st_fifo->pending_bytes < self->io.fifo_size) { - switch_bank(iobase, BANK0); - if (inb(iobase+LSR) & LSR_RXDA) { - /* Put this entry back in fifo */ - st_fifo->head--; - st_fifo->len++; - st_fifo->pending_bytes += len; - st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[st_fifo->head].len = len; - /* - * DMA not finished yet, so try again - * later, set timer value, resolution - * 125 us - */ - switch_bank(iobase, BANK4); - outb(0x02, iobase+TMRL); /* x 125 us */ - outb(0x00, iobase+TMRH); - - /* Start timer */ - outb(IRCR1_TMR_EN, iobase+IRCR1); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - return FALSE; /* I'll be back! */ - } - } - - /* - * Remember the time we received this frame, so we can - * reduce the min turn time a bit since we will know - * how much time we have used for protocol processing - */ - self->stamp = ktime_get(); - - skb = dev_alloc_skb(len+1); - if (skb == NULL) { - self->netdev->stats.rx_dropped++; - - /* Restore bank register */ - outb(bank, iobase+BSR); - - return FALSE; - } - - /* Make sure IP header gets aligned */ - skb_reserve(skb, 1); - - /* Copy frame without CRC */ - if (self->io.speed < 4000000) { - skb_put(skb, len-2); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 2); - } else { - skb_put(skb, len-4); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 4); - } - - /* Move to next frame */ - self->rx_buff.data += len; - self->netdev->stats.rx_bytes += len; - self->netdev->stats.rx_packets++; - - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - } - } - /* Restore bank register */ - outb(bank, iobase+BSR); - - return TRUE; -} - -/* - * Function nsc_ircc_pio_receive (self) - * - * Receive all data in receiver FIFO - * - */ -static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) -{ - __u8 byte; - int iobase; - - iobase = self->io.fir_base; - - /* Receive all characters in Rx FIFO */ - do { - byte = inb(iobase+RXD); - async_unwrap_char(self->netdev, &self->netdev->stats, - &self->rx_buff, byte); - } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ -} - -/* - * Function nsc_ircc_sir_interrupt (self, eir) - * - * Handle SIR interrupt - * - */ -static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) -{ - int actual; - - /* Check if transmit FIFO is low on data */ - if (eir & EIR_TXLDL_EV) { - /* Write data left in transmit buffer */ - actual = nsc_ircc_pio_write(self->io.fir_base, - self->tx_buff.data, - self->tx_buff.len, - self->io.fifo_size); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - - self->io.direction = IO_XMIT; - - /* Check if finished */ - if (self->tx_buff.len > 0) - self->ier = IER_TXLDL_IE; - else { - - self->netdev->stats.tx_packets++; - netif_wake_queue(self->netdev); - self->ier = IER_TXEMP_IE; - } - - } - /* Check if transmission has completed */ - if (eir & EIR_TXEMP_EV) { - /* Turn around and get ready to receive some data */ - self->io.direction = IO_RECV; - self->ier = IER_RXHDL_IE; - /* Check if we need to change the speed? - * Need to be after self->io.direction to avoid race with - * nsc_ircc_hard_xmit_sir() - Jean II */ - if (self->new_speed) { - pr_debug("%s(), Changing speed!\n", __func__); - self->ier = nsc_ircc_change_speed(self, - self->new_speed); - self->new_speed = 0; - netif_wake_queue(self->netdev); - - /* Check if we are going to FIR */ - if (self->io.speed > 115200) { - /* No need to do anymore SIR stuff */ - return; - } - } - } - - /* Rx FIFO threshold or timeout */ - if (eir & EIR_RXHDL_EV) { - nsc_ircc_pio_receive(self); - - /* Keep receiving */ - self->ier = IER_RXHDL_IE; - } -} - -/* - * Function nsc_ircc_fir_interrupt (self, eir) - * - * Handle MIR/FIR interrupt - * - */ -static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, - int eir) -{ - __u8 bank; - - bank = inb(iobase+BSR); - - /* Status FIFO event*/ - if (eir & EIR_SFIF_EV) { - /* Check if DMA has finished */ - if (nsc_ircc_dma_receive_complete(self, iobase)) { - /* Wait for next status FIFO interrupt */ - self->ier = IER_SFIF_IE; - } else { - self->ier = IER_SFIF_IE | IER_TMR_IE; - } - } else if (eir & EIR_TMR_EV) { /* Timer finished */ - /* Disable timer */ - switch_bank(iobase, BANK4); - outb(0, iobase+IRCR1); - - /* Clear timer event */ - switch_bank(iobase, BANK0); - outb(ASCR_CTE, iobase+ASCR); - - /* Check if this is a Tx timer interrupt */ - if (self->io.direction == IO_XMIT) { - nsc_ircc_dma_xmit(self, iobase); - - /* Interrupt on DMA */ - self->ier = IER_DMA_IE; - } else { - /* Check (again) if DMA has finished */ - if (nsc_ircc_dma_receive_complete(self, iobase)) { - self->ier = IER_SFIF_IE; - } else { - self->ier = IER_SFIF_IE | IER_TMR_IE; - } - } - } else if (eir & EIR_DMA_EV) { - /* Finished with all transmissions? */ - if (nsc_ircc_dma_xmit_complete(self)) { - if(self->new_speed != 0) { - /* As we stop the Tx queue, the speed change - * need to be done when the Tx fifo is - * empty. Ask for a Tx done interrupt */ - self->ier = IER_TXEMP_IE; - } else { - /* Check if there are more frames to be - * transmitted */ - if (irda_device_txqueue_empty(self->netdev)) { - /* Prepare for receive */ - nsc_ircc_dma_receive(self); - self->ier = IER_SFIF_IE; - } else - net_warn_ratelimited("%s(), potential Tx queue lockup !\n", - __func__); - } - } else { - /* Not finished yet, so interrupt on DMA again */ - self->ier = IER_DMA_IE; - } - } else if (eir & EIR_TXEMP_EV) { - /* The Tx FIFO has totally drained out, so now we can change - * the speed... - Jean II */ - self->ier = nsc_ircc_change_speed(self, self->new_speed); - self->new_speed = 0; - netif_wake_queue(self->netdev); - /* Note : nsc_ircc_change_speed() restarted Rx fifo */ - } - - outb(bank, iobase+BSR); -} - -/* - * Function nsc_ircc_interrupt (irq, dev_id, regs) - * - * An interrupt from the chip has arrived. Time to do some work - * - */ -static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct nsc_ircc_cb *self; - __u8 bsr, eir; - int iobase; - - self = netdev_priv(dev); - - spin_lock(&self->lock); - - iobase = self->io.fir_base; - - bsr = inb(iobase+BSR); /* Save current bank */ - - switch_bank(iobase, BANK0); - self->ier = inb(iobase+IER); - eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */ - - outb(0, iobase+IER); /* Disable interrupts */ - - if (eir) { - /* Dispatch interrupt handler for the current speed */ - if (self->io.speed > 115200) - nsc_ircc_fir_interrupt(self, iobase, eir); - else - nsc_ircc_sir_interrupt(self, eir); - } - - outb(self->ier, iobase+IER); /* Restore interrupts */ - outb(bsr, iobase+BSR); /* Restore bank register */ - - spin_unlock(&self->lock); - return IRQ_RETVAL(eir); -} - -/* - * Function nsc_ircc_is_receiving (self) - * - * Return TRUE is we are currently receiving a frame - * - */ -static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self) -{ - unsigned long flags; - int status = FALSE; - int iobase; - __u8 bank; - - IRDA_ASSERT(self != NULL, return FALSE;); - - spin_lock_irqsave(&self->lock, flags); - - if (self->io.speed > 115200) { - iobase = self->io.fir_base; - - /* Check if rx FIFO is not empty */ - bank = inb(iobase+BSR); - switch_bank(iobase, BANK2); - if ((inb(iobase+RXFLV) & 0x3f) != 0) { - /* We are receiving something */ - status = TRUE; - } - outb(bank, iobase+BSR); - } else - status = (self->rx_buff.state != OUTSIDE_FRAME); - - spin_unlock_irqrestore(&self->lock, flags); - - return status; -} - -/* - * Function nsc_ircc_net_open (dev) - * - * Start the device - * - */ -static int nsc_ircc_net_open(struct net_device *dev) -{ - struct nsc_ircc_cb *self; - int iobase; - char hwname[32]; - __u8 bank; - - - IRDA_ASSERT(dev != NULL, return -1;); - self = netdev_priv(dev); - - IRDA_ASSERT(self != NULL, return 0;); - - iobase = self->io.fir_base; - - if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) { - net_warn_ratelimited("%s, unable to allocate irq=%d\n", - driver_name, self->io.irq); - return -EAGAIN; - } - /* - * Always allocate the DMA channel after the IRQ, and clean up on - * failure. - */ - if (request_dma(self->io.dma, dev->name)) { - net_warn_ratelimited("%s, unable to allocate dma=%d\n", - driver_name, self->io.dma); - free_irq(self->io.irq, dev); - return -EAGAIN; - } - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* turn on interrupts */ - switch_bank(iobase, BANK0); - outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - /* Ready to play! */ - netif_start_queue(dev); - - /* Give self a hardware name */ - sprintf(hwname, "NSC-FIR @ 0x%03x", self->io.fir_base); - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos, hwname); - - return 0; -} - -/* - * Function nsc_ircc_net_close (dev) - * - * Stop the device - * - */ -static int nsc_ircc_net_close(struct net_device *dev) -{ - struct nsc_ircc_cb *self; - int iobase; - __u8 bank; - - - IRDA_ASSERT(dev != NULL, return -1;); - - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); - - /* Stop device */ - netif_stop_queue(dev); - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - iobase = self->io.fir_base; - - disable_dma(self->io.dma); - - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable interrupts */ - switch_bank(iobase, BANK0); - outb(0, iobase+IER); - - free_irq(self->io.irq, dev); - free_dma(self->io.dma); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - return 0; -} - -/* - * Function nsc_ircc_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct nsc_ircc_cb *self; - unsigned long flags; - int ret = 0; - - IRDA_ASSERT(dev != NULL, return -1;); - - self = netdev_priv(dev); - - IRDA_ASSERT(self != NULL, return -1;); - - pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - spin_lock_irqsave(&self->lock, flags); - nsc_ircc_change_speed(self, irq->ifr_baudrate); - spin_unlock_irqrestore(&self->lock, flags); - break; - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - /* This is already protected */ - irq->ifr_receiving = nsc_ircc_is_receiving(self); - break; - default: - ret = -EOPNOTSUPP; - } - return ret; -} - -static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state) -{ - struct nsc_ircc_cb *self = platform_get_drvdata(dev); - int bank; - unsigned long flags; - int iobase = self->io.fir_base; - - if (self->io.suspended) - return 0; - - pr_debug("%s, Suspending\n", driver_name); - - rtnl_lock(); - if (netif_running(self->netdev)) { - netif_device_detach(self->netdev); - spin_lock_irqsave(&self->lock, flags); - /* Save current bank */ - bank = inb(iobase+BSR); - - /* Disable interrupts */ - switch_bank(iobase, BANK0); - outb(0, iobase+IER); - - /* Restore bank register */ - outb(bank, iobase+BSR); - - spin_unlock_irqrestore(&self->lock, flags); - free_irq(self->io.irq, self->netdev); - disable_dma(self->io.dma); - } - self->io.suspended = 1; - rtnl_unlock(); - - return 0; -} - -static int nsc_ircc_resume(struct platform_device *dev) -{ - struct nsc_ircc_cb *self = platform_get_drvdata(dev); - unsigned long flags; - - if (!self->io.suspended) - return 0; - - pr_debug("%s, Waking up\n", driver_name); - - rtnl_lock(); - nsc_ircc_setup(&self->io); - nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id); - - if (netif_running(self->netdev)) { - if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, - self->netdev->name, self->netdev)) { - net_warn_ratelimited("%s, unable to allocate irq=%d\n", - driver_name, self->io.irq); - - /* - * Don't fail resume process, just kill this - * network interface - */ - unregister_netdevice(self->netdev); - } else { - spin_lock_irqsave(&self->lock, flags); - nsc_ircc_change_speed(self, self->io.speed); - spin_unlock_irqrestore(&self->lock, flags); - netif_device_attach(self->netdev); - } - - } else { - spin_lock_irqsave(&self->lock, flags); - nsc_ircc_change_speed(self, 9600); - spin_unlock_irqrestore(&self->lock, flags); - } - self->io.suspended = 0; - rtnl_unlock(); - - return 0; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("NSC IrDA Device Driver"); -MODULE_LICENSE("GPL"); - - -module_param(qos_mtt_bits, int, 0); -MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); -module_param_hw_array(io, int, ioport, NULL, 0); -MODULE_PARM_DESC(io, "Base I/O addresses"); -module_param_hw_array(irq, int, irq, NULL, 0); -MODULE_PARM_DESC(irq, "IRQ lines"); -module_param_hw_array(dma, int, dma, NULL, 0); -MODULE_PARM_DESC(dma, "DMA channels"); -module_param(dongle_id, int, 0); -MODULE_PARM_DESC(dongle_id, "Type-id of used dongle"); - -module_init(nsc_ircc_init); -module_exit(nsc_ircc_cleanup); - diff --git a/drivers/staging/irda/drivers/nsc-ircc.h b/drivers/staging/irda/drivers/nsc-ircc.h deleted file mode 100644 index 7be5acb56532..000000000000 --- a/drivers/staging/irda/drivers/nsc-ircc.h +++ /dev/null @@ -1,281 +0,0 @@ -/********************************************************************* - * - * Filename: nsc-ircc.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri Nov 13 14:37:40 1998 - * Modified at: Sun Jan 23 17:47:00 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1998 Lichen Wang, <lwang@actisys.com> - * Copyright (c) 1998 Actisys Corp., www.actisys.com - * All Rights Reserved - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef NSC_IRCC_H -#define NSC_IRCC_H - -#include <linux/ktime.h> - -#include <linux/spinlock.h> -#include <linux/pm.h> -#include <linux/types.h> -#include <asm/io.h> - -/* Features for chips (set in driver_data) */ -#define NSC_FORCE_DONGLE_TYPE9 0x00000001 - -/* DMA modes needed */ -#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ -#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ - -/* Config registers for the '108 */ -#define CFG_108_BAIC 0x00 -#define CFG_108_CSRT 0x01 -#define CFG_108_MCTL 0x02 - -/* Config registers for the '338 */ -#define CFG_338_FER 0x00 -#define CFG_338_FAR 0x01 -#define CFG_338_PTR 0x02 -#define CFG_338_PNP0 0x1b -#define CFG_338_PNP1 0x1c -#define CFG_338_PNP3 0x4f - -/* Config registers for the '39x (in the logical device bank) */ -#define CFG_39X_LDN 0x07 /* Logical device number (Super I/O bank) */ -#define CFG_39X_SIOCF1 0x21 /* SuperI/O Config */ -#define CFG_39X_ACT 0x30 /* Device activation */ -#define CFG_39X_BASEH 0x60 /* Device base address (high bits) */ -#define CFG_39X_BASEL 0x61 /* Device base address (low bits) */ -#define CFG_39X_IRQNUM 0x70 /* Interrupt number & wake up enable */ -#define CFG_39X_IRQSEL 0x71 /* Interrupt select (edge/level + polarity) */ -#define CFG_39X_DMA0 0x74 /* DMA 0 configuration */ -#define CFG_39X_DMA1 0x75 /* DMA 1 configuration */ -#define CFG_39X_SPC 0xF0 /* Serial port configuration register */ - -/* Flags for configuration register CRF0 */ -#define APEDCRC 0x02 -#define ENBNKSEL 0x01 - -/* Set 0 */ -#define TXD 0x00 /* Transmit data port */ -#define RXD 0x00 /* Receive data port */ - -/* Register 1 */ -#define IER 0x01 /* Interrupt Enable Register*/ -#define IER_RXHDL_IE 0x01 /* Receiver high data level interrupt */ -#define IER_TXLDL_IE 0x02 /* Transeiver low data level interrupt */ -#define IER_LS_IE 0x04//* Link Status Interrupt */ -#define IER_ETXURI 0x04 /* Tx underrun */ -#define IER_DMA_IE 0x10 /* DMA finished interrupt */ -#define IER_TXEMP_IE 0x20 -#define IER_SFIF_IE 0x40 /* Frame status FIFO intr */ -#define IER_TMR_IE 0x80 /* Timer event */ - -#define FCR 0x02 /* (write only) */ -#define FCR_FIFO_EN 0x01 /* Enable FIFO's */ -#define FCR_RXSR 0x02 /* Rx FIFO soft reset */ -#define FCR_TXSR 0x04 /* Tx FIFO soft reset */ -#define FCR_RXTH 0x40 /* Rx FIFO threshold (set to 16) */ -#define FCR_TXTH 0x20 /* Tx FIFO threshold (set to 17) */ - -#define EIR 0x02 /* (read only) */ -#define EIR_RXHDL_EV 0x01 -#define EIR_TXLDL_EV 0x02 -#define EIR_LS_EV 0x04 -#define EIR_DMA_EV 0x10 -#define EIR_TXEMP_EV 0x20 -#define EIR_SFIF_EV 0x40 -#define EIR_TMR_EV 0x80 - -#define LCR 0x03 /* Link control register */ -#define LCR_WLS_8 0x03 /* 8 bits */ - -#define BSR 0x03 /* Bank select register */ -#define BSR_BKSE 0x80 -#define BANK0 LCR_WLS_8 /* Must make sure that we set 8N1 */ -#define BANK1 0x80 -#define BANK2 0xe0 -#define BANK3 0xe4 -#define BANK4 0xe8 -#define BANK5 0xec -#define BANK6 0xf0 -#define BANK7 0xf4 - -#define MCR 0x04 /* Mode Control Register */ -#define MCR_MODE_MASK ~(0xd0) -#define MCR_UART 0x00 -#define MCR_RESERVED 0x20 -#define MCR_SHARP_IR 0x40 -#define MCR_SIR 0x60 -#define MCR_MIR 0x80 -#define MCR_FIR 0xa0 -#define MCR_CEIR 0xb0 -#define MCR_IR_PLS 0x10 -#define MCR_DMA_EN 0x04 -#define MCR_EN_IRQ 0x08 -#define MCR_TX_DFR 0x08 - -#define LSR 0x05 /* Link status register */ -#define LSR_RXDA 0x01 /* Receiver data available */ -#define LSR_TXRDY 0x20 /* Transmitter ready */ -#define LSR_TXEMP 0x40 /* Transmitter empty */ - -#define ASCR 0x07 /* Auxiliary Status and Control Register */ -#define ASCR_RXF_TOUT 0x01 /* Rx FIFO timeout */ -#define ASCR_FEND_INF 0x02 /* Frame end bytes in rx FIFO */ -#define ASCR_S_EOT 0x04 /* Set end of transmission */ -#define ASCT_RXBSY 0x20 /* Rx busy */ -#define ASCR_TXUR 0x40 /* Transeiver underrun */ -#define ASCR_CTE 0x80 /* Clear timer event */ - -/* Bank 2 */ -#define BGDL 0x00 /* Baud Generator Divisor Port (Low Byte) */ -#define BGDH 0x01 /* Baud Generator Divisor Port (High Byte) */ - -#define ECR1 0x02 /* Extended Control Register 1 */ -#define ECR1_EXT_SL 0x01 /* Extended Mode Select */ -#define ECR1_DMANF 0x02 /* DMA Fairness */ -#define ECR1_DMATH 0x04 /* DMA Threshold */ -#define ECR1_DMASWP 0x08 /* DMA Swap */ - -#define EXCR2 0x04 -#define EXCR2_TFSIZ 0x01 /* Rx FIFO size = 32 */ -#define EXCR2_RFSIZ 0x04 /* Tx FIFO size = 32 */ - -#define TXFLV 0x06 /* Tx FIFO level */ -#define RXFLV 0x07 /* Rx FIFO level */ - -/* Bank 3 */ -#define MID 0x00 - -/* Bank 4 */ -#define TMRL 0x00 /* Timer low byte */ -#define TMRH 0x01 /* Timer high byte */ -#define IRCR1 0x02 /* Infrared control register 1 */ -#define IRCR1_TMR_EN 0x01 /* Timer enable */ - -#define TFRLL 0x04 -#define TFRLH 0x05 -#define RFRLL 0x06 -#define RFRLH 0x07 - -/* Bank 5 */ -#define IRCR2 0x04 /* Infrared control register 2 */ -#define IRCR2_MDRS 0x04 /* MIR data rate select */ -#define IRCR2_FEND_MD 0x20 /* */ - -#define FRM_ST 0x05 /* Frame status FIFO */ -#define FRM_ST_VLD 0x80 /* Frame status FIFO data valid */ -#define FRM_ST_ERR_MSK 0x5f -#define FRM_ST_LOST_FR 0x40 /* Frame lost */ -#define FRM_ST_MAX_LEN 0x10 /* Max frame len exceeded */ -#define FRM_ST_PHY_ERR 0x08 /* Physical layer error */ -#define FRM_ST_BAD_CRC 0x04 -#define FRM_ST_OVR1 0x02 /* Rx FIFO overrun */ -#define FRM_ST_OVR2 0x01 /* Frame status FIFO overrun */ - -#define RFLFL 0x06 -#define RFLFH 0x07 - -/* Bank 6 */ -#define IR_CFG2 0x00 -#define IR_CFG2_DIS_CRC 0x02 - -/* Bank 7 */ -#define IRM_CR 0x07 /* Infrared module control register */ -#define IRM_CR_IRX_MSL 0x40 -#define IRM_CR_AF_MNT 0x80 /* Automatic format */ - -/* NSC chip information */ -struct nsc_chip { - char *name; /* Name of chipset */ - int cfg[3]; /* Config registers */ - u_int8_t cid_index; /* Chip identification index reg */ - u_int8_t cid_value; /* Chip identification expected value */ - u_int8_t cid_mask; /* Chip identification revision mask */ - - /* Functions for probing and initializing the specific chip */ - int (*probe)(struct nsc_chip *chip, chipio_t *info); - int (*init)(struct nsc_chip *chip, chipio_t *info); -}; -typedef struct nsc_chip nsc_chip_t; - -/* For storing entries in the status FIFO */ -struct st_fifo_entry { - int status; - int len; -}; - -#define MAX_TX_WINDOW 7 -#define MAX_RX_WINDOW 7 - -struct st_fifo { - struct st_fifo_entry entries[MAX_RX_WINDOW]; - int pending_bytes; - int head; - int tail; - int len; -}; - -struct frame_cb { - void *start; /* Start of frame in DMA mem */ - int len; /* Length of frame in DMA mem */ -}; - -struct tx_fifo { - struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */ - int ptr; /* Currently being sent */ - int len; /* Length of queue */ - int free; /* Next free slot */ - void *tail; /* Next free start in DMA mem */ -}; - -/* Private data for each instance */ -struct nsc_ircc_cb { - struct st_fifo st_fifo; /* Info about received frames */ - struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ - - struct net_device *netdev; /* Yes! we are some kind of netdevice */ - - struct irlap_cb *irlap; /* The link layer we are binded to */ - struct qos_info qos; /* QoS capabilities for this device */ - - chipio_t io; /* IrDA controller information */ - iobuff_t tx_buff; /* Transmit buffer */ - iobuff_t rx_buff; /* Receive buffer */ - dma_addr_t tx_buff_dma; - dma_addr_t rx_buff_dma; - - __u8 ier; /* Interrupt enable register */ - - ktime_t stamp; - - spinlock_t lock; /* For serializing operations */ - - __u32 new_speed; - int index; /* Instance index */ - - struct platform_device *pldev; -}; - -static inline void switch_bank(int iobase, int bank) -{ - outb(bank, iobase+BSR); -} - -#endif /* NSC_IRCC_H */ diff --git a/drivers/staging/irda/drivers/old_belkin-sir.c b/drivers/staging/irda/drivers/old_belkin-sir.c deleted file mode 100644 index a7c2e990ae69..000000000000 --- a/drivers/staging/irda/drivers/old_belkin-sir.c +++ /dev/null @@ -1,146 +0,0 @@ -/********************************************************************* - * - * Filename: old_belkin.c - * Version: 1.1 - * Description: Driver for the Belkin (old) SmartBeam dongle - * Status: Experimental... - * Author: Jean Tourrilhes <jt@hpl.hp.com> - * Created at: 22/11/99 - * Modified at: Fri Dec 17 09:13:32 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Jean Tourrilhes, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -// #include <net/irda/irda_device.h> - -#include "sir-dev.h" - -/* - * Belkin is selling a dongle called the SmartBeam. - * In fact, there is two hardware version of this dongle, of course with - * the same name and looking the exactly same (grrr...). - * I guess that I've got the old one, because inside I don't have - * a jumper for IrDA/ASK... - * - * As far as I can make it from info on their web site, the old dongle - * support only 9600 b/s, which make our life much simpler as far as - * the driver is concerned, but you might not like it very much ;-) - * The new SmartBeam does 115 kb/s, and I've not tested it... - * - * Belkin claim that the correct driver for the old dongle (in Windows) - * is the generic Parallax 9500a driver, but the Linux LiteLink driver - * fails for me (probably because Linux-IrDA doesn't rate fallback), - * so I created this really dumb driver... - * - * In fact, this driver doesn't do much. The only thing it does is to - * prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This - * driver is called "old_belkin" so that when the new SmartBeam is supported - * its driver can be called "belkin" instead of "new_belkin". - * - * Note : this driver was written without any info/help from Belkin, - * so a lot of info here might be totally wrong. Blame me ;-) - */ - -static int old_belkin_open(struct sir_dev *dev); -static int old_belkin_close(struct sir_dev *dev); -static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed); -static int old_belkin_reset(struct sir_dev *dev); - -static struct dongle_driver old_belkin = { - .owner = THIS_MODULE, - .driver_name = "Old Belkin SmartBeam", - .type = IRDA_OLD_BELKIN_DONGLE, - .open = old_belkin_open, - .close = old_belkin_close, - .reset = old_belkin_reset, - .set_speed = old_belkin_change_speed, -}; - -static int __init old_belkin_sir_init(void) -{ - return irda_register_dongle(&old_belkin); -} - -static void __exit old_belkin_sir_cleanup(void) -{ - irda_unregister_dongle(&old_belkin); -} - -static int old_belkin_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - /* Power on dongle */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Not too fast, please... */ - qos->baud_rate.bits &= IR_9600; - /* Needs at least 10 ms (totally wild guess, can do probably better) */ - qos->min_turn_time.bits = 0x01; - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int old_belkin_close(struct sir_dev *dev) -{ - /* Power off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function old_belkin_change_speed (task) - * - * With only one speed available, not much to do... - */ -static int old_belkin_change_speed(struct sir_dev *dev, unsigned speed) -{ - dev->speed = 9600; - return (speed==dev->speed) ? 0 : -EINVAL; -} - -/* - * Function old_belkin_reset (task) - * - * Reset the Old-Belkin type dongle. - * - */ -static int old_belkin_reset(struct sir_dev *dev) -{ - /* This dongles speed "defaults" to 9600 bps ;-) */ - dev->speed = 9600; - - return 0; -} - -MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); -MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-7"); /* IRDA_OLD_BELKIN_DONGLE */ - -module_init(old_belkin_sir_init); -module_exit(old_belkin_sir_cleanup); diff --git a/drivers/staging/irda/drivers/pxaficp_ir.c b/drivers/staging/irda/drivers/pxaficp_ir.c deleted file mode 100644 index 2ea00a6531f9..000000000000 --- a/drivers/staging/irda/drivers/pxaficp_ir.c +++ /dev/null @@ -1,1075 +0,0 @@ -/* - * linux/drivers/net/irda/pxaficp_ir.c - * - * Based on sa1100_ir.c by Russell King - * - * Changes copyright (C) 2003-2005 MontaVista Software, Inc. - * - * 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. - * - * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor - * - */ -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/dmaengine.h> -#include <linux/dma-mapping.h> -#include <linux/dma/pxa-dma.h> -#include <linux/gpio.h> -#include <linux/slab.h> -#include <linux/sched/clock.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> -#include <net/irda/wrapper.h> -#include <net/irda/irda_device.h> - -#include <linux/platform_data/irda-pxaficp.h> -#undef __REG -#define __REG(x) ((x) & 0xffff) -#include <mach/regs-uart.h> - -#define ICCR0 0x0000 /* ICP Control Register 0 */ -#define ICCR1 0x0004 /* ICP Control Register 1 */ -#define ICCR2 0x0008 /* ICP Control Register 2 */ -#define ICDR 0x000c /* ICP Data Register */ -#define ICSR0 0x0014 /* ICP Status Register 0 */ -#define ICSR1 0x0018 /* ICP Status Register 1 */ - -#define ICCR0_AME (1 << 7) /* Address match enable */ -#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */ -#define ICCR0_RIE (1 << 5) /* Receive FIFO interrupt enable */ -#define ICCR0_RXE (1 << 4) /* Receive enable */ -#define ICCR0_TXE (1 << 3) /* Transmit enable */ -#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */ -#define ICCR0_LBM (1 << 1) /* Loopback mode */ -#define ICCR0_ITR (1 << 0) /* IrDA transmission */ - -#define ICCR2_RXP (1 << 3) /* Receive Pin Polarity select */ -#define ICCR2_TXP (1 << 2) /* Transmit Pin Polarity select */ -#define ICCR2_TRIG (3 << 0) /* Receive FIFO Trigger threshold */ -#define ICCR2_TRIG_8 (0 << 0) /* >= 8 bytes */ -#define ICCR2_TRIG_16 (1 << 0) /* >= 16 bytes */ -#define ICCR2_TRIG_32 (2 << 0) /* >= 32 bytes */ - -#define ICSR0_EOC (1 << 6) /* DMA End of Descriptor Chain */ -#define ICSR0_FRE (1 << 5) /* Framing error */ -#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */ -#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */ -#define ICSR0_RAB (1 << 2) /* Receiver abort */ -#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */ -#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */ - -#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */ -#define ICSR1_CRE (1 << 5) /* CRC error */ -#define ICSR1_EOF (1 << 4) /* End of frame */ -#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */ -#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */ -#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */ -#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */ - -#define IrSR_RXPL_NEG_IS_ZERO (1<<4) -#define IrSR_RXPL_POS_IS_ZERO 0x0 -#define IrSR_TXPL_NEG_IS_ZERO (1<<3) -#define IrSR_TXPL_POS_IS_ZERO 0x0 -#define IrSR_XMODE_PULSE_1_6 (1<<2) -#define IrSR_XMODE_PULSE_3_16 0x0 -#define IrSR_RCVEIR_IR_MODE (1<<1) -#define IrSR_RCVEIR_UART_MODE 0x0 -#define IrSR_XMITIR_IR_MODE (1<<0) -#define IrSR_XMITIR_UART_MODE 0x0 - -#define IrSR_IR_RECEIVE_ON (\ - IrSR_RXPL_NEG_IS_ZERO | \ - IrSR_TXPL_POS_IS_ZERO | \ - IrSR_XMODE_PULSE_3_16 | \ - IrSR_RCVEIR_IR_MODE | \ - IrSR_XMITIR_UART_MODE) - -#define IrSR_IR_TRANSMIT_ON (\ - IrSR_RXPL_NEG_IS_ZERO | \ - IrSR_TXPL_POS_IS_ZERO | \ - IrSR_XMODE_PULSE_3_16 | \ - IrSR_RCVEIR_UART_MODE | \ - IrSR_XMITIR_IR_MODE) - -/* macros for registers read/write */ -#define ficp_writel(irda, val, off) \ - do { \ - dev_vdbg(irda->dev, \ - "%s():%d ficp_writel(0x%x, %s)\n", \ - __func__, __LINE__, (val), #off); \ - writel_relaxed((val), (irda)->irda_base + (off)); \ - } while (0) - -#define ficp_readl(irda, off) \ - ({ \ - unsigned int _v; \ - _v = readl_relaxed((irda)->irda_base + (off)); \ - dev_vdbg(irda->dev, \ - "%s():%d ficp_readl(%s): 0x%x\n", \ - __func__, __LINE__, #off, _v); \ - _v; \ - }) - -#define stuart_writel(irda, val, off) \ - do { \ - dev_vdbg(irda->dev, \ - "%s():%d stuart_writel(0x%x, %s)\n", \ - __func__, __LINE__, (val), #off); \ - writel_relaxed((val), (irda)->stuart_base + (off)); \ - } while (0) - -#define stuart_readl(irda, off) \ - ({ \ - unsigned int _v; \ - _v = readl_relaxed((irda)->stuart_base + (off)); \ - dev_vdbg(irda->dev, \ - "%s():%d stuart_readl(%s): 0x%x\n", \ - __func__, __LINE__, #off, _v); \ - _v; \ - }) - -struct pxa_irda { - int speed; - int newspeed; - unsigned long long last_clk; - - void __iomem *stuart_base; - void __iomem *irda_base; - unsigned char *dma_rx_buff; - unsigned char *dma_tx_buff; - dma_addr_t dma_rx_buff_phy; - dma_addr_t dma_tx_buff_phy; - unsigned int dma_tx_buff_len; - struct dma_chan *txdma; - struct dma_chan *rxdma; - dma_cookie_t rx_cookie; - dma_cookie_t tx_cookie; - int drcmr_rx; - int drcmr_tx; - - int uart_irq; - int icp_irq; - - struct irlap_cb *irlap; - struct qos_info qos; - - iobuff_t tx_buff; - iobuff_t rx_buff; - - struct device *dev; - struct pxaficp_platform_data *pdata; - struct clk *fir_clk; - struct clk *sir_clk; - struct clk *cur_clk; -}; - -static int pxa_irda_set_speed(struct pxa_irda *si, int speed); - -static inline void pxa_irda_disable_clk(struct pxa_irda *si) -{ - if (si->cur_clk) - clk_disable_unprepare(si->cur_clk); - si->cur_clk = NULL; -} - -static inline void pxa_irda_enable_firclk(struct pxa_irda *si) -{ - si->cur_clk = si->fir_clk; - clk_prepare_enable(si->fir_clk); -} - -static inline void pxa_irda_enable_sirclk(struct pxa_irda *si) -{ - si->cur_clk = si->sir_clk; - clk_prepare_enable(si->sir_clk); -} - - -#define IS_FIR(si) ((si)->speed >= 4000000) -#define IRDA_FRAME_SIZE_LIMIT 2047 - -static void pxa_irda_fir_dma_rx_irq(void *data); -static void pxa_irda_fir_dma_tx_irq(void *data); - -inline static void pxa_irda_fir_dma_rx_start(struct pxa_irda *si) -{ - struct dma_async_tx_descriptor *tx; - - tx = dmaengine_prep_slave_single(si->rxdma, si->dma_rx_buff_phy, - IRDA_FRAME_SIZE_LIMIT, DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT); - if (!tx) { - dev_err(si->dev, "prep_slave_sg() failed\n"); - return; - } - tx->callback = pxa_irda_fir_dma_rx_irq; - tx->callback_param = si; - si->rx_cookie = dmaengine_submit(tx); - dma_async_issue_pending(si->rxdma); -} - -inline static void pxa_irda_fir_dma_tx_start(struct pxa_irda *si) -{ - struct dma_async_tx_descriptor *tx; - - tx = dmaengine_prep_slave_single(si->txdma, si->dma_tx_buff_phy, - si->dma_tx_buff_len, DMA_TO_DEVICE, - DMA_PREP_INTERRUPT); - if (!tx) { - dev_err(si->dev, "prep_slave_sg() failed\n"); - return; - } - tx->callback = pxa_irda_fir_dma_tx_irq; - tx->callback_param = si; - si->tx_cookie = dmaengine_submit(tx); - dma_async_issue_pending(si->rxdma); -} - -/* - * Set the IrDA communications mode. - */ -static void pxa_irda_set_mode(struct pxa_irda *si, int mode) -{ - if (si->pdata->transceiver_mode) - si->pdata->transceiver_mode(si->dev, mode); - else { - if (gpio_is_valid(si->pdata->gpio_pwdown)) - gpio_set_value(si->pdata->gpio_pwdown, - !(mode & IR_OFF) ^ - !si->pdata->gpio_pwdown_inverted); - pxa2xx_transceiver_mode(si->dev, mode); - } -} - -/* - * Set the IrDA communications speed. - */ -static int pxa_irda_set_speed(struct pxa_irda *si, int speed) -{ - unsigned long flags; - unsigned int divisor; - - switch (speed) { - case 9600: case 19200: case 38400: - case 57600: case 115200: - - /* refer to PXA250/210 Developer's Manual 10-7 */ - /* BaudRate = 14.7456 MHz / (16*Divisor) */ - divisor = 14745600 / (16 * speed); - - local_irq_save(flags); - - if (IS_FIR(si)) { - /* stop RX DMA */ - dmaengine_terminate_all(si->rxdma); - /* disable FICP */ - ficp_writel(si, 0, ICCR0); - pxa_irda_disable_clk(si); - - /* set board transceiver to SIR mode */ - pxa_irda_set_mode(si, IR_SIRMODE); - - /* enable the STUART clock */ - pxa_irda_enable_sirclk(si); - } - - /* disable STUART first */ - stuart_writel(si, 0, STIER); - - /* access DLL & DLH */ - stuart_writel(si, stuart_readl(si, STLCR) | LCR_DLAB, STLCR); - stuart_writel(si, divisor & 0xff, STDLL); - stuart_writel(si, divisor >> 8, STDLH); - stuart_writel(si, stuart_readl(si, STLCR) & ~LCR_DLAB, STLCR); - - si->speed = speed; - stuart_writel(si, IrSR_IR_RECEIVE_ON | IrSR_XMODE_PULSE_1_6, - STISR); - stuart_writel(si, IER_UUE | IER_RLSE | IER_RAVIE | IER_RTIOE, - STIER); - - local_irq_restore(flags); - break; - - case 4000000: - local_irq_save(flags); - - /* disable STUART */ - stuart_writel(si, 0, STIER); - stuart_writel(si, 0, STISR); - pxa_irda_disable_clk(si); - - /* disable FICP first */ - ficp_writel(si, 0, ICCR0); - - /* set board transceiver to FIR mode */ - pxa_irda_set_mode(si, IR_FIRMODE); - - /* enable the FICP clock */ - pxa_irda_enable_firclk(si); - - si->speed = speed; - pxa_irda_fir_dma_rx_start(si); - ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); - - local_irq_restore(flags); - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* SIR interrupt service routine. */ -static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct pxa_irda *si = netdev_priv(dev); - int iir, lsr, data; - - iir = stuart_readl(si, STIIR); - - switch (iir & 0x0F) { - case 0x06: /* Receiver Line Status */ - lsr = stuart_readl(si, STLSR); - while (lsr & LSR_FIFOE) { - data = stuart_readl(si, STRBR); - if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { - printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); - dev->stats.rx_errors++; - if (lsr & LSR_FE) - dev->stats.rx_frame_errors++; - if (lsr & LSR_OE) - dev->stats.rx_fifo_errors++; - } else { - dev->stats.rx_bytes++; - async_unwrap_char(dev, &dev->stats, - &si->rx_buff, data); - } - lsr = stuart_readl(si, STLSR); - } - si->last_clk = sched_clock(); - break; - - case 0x04: /* Received Data Available */ - /* forth through */ - - case 0x0C: /* Character Timeout Indication */ - do { - dev->stats.rx_bytes++; - async_unwrap_char(dev, &dev->stats, &si->rx_buff, - stuart_readl(si, STRBR)); - } while (stuart_readl(si, STLSR) & LSR_DR); - si->last_clk = sched_clock(); - break; - - case 0x02: /* Transmit FIFO Data Request */ - while ((si->tx_buff.len) && - (stuart_readl(si, STLSR) & LSR_TDRQ)) { - stuart_writel(si, *si->tx_buff.data++, STTHR); - si->tx_buff.len -= 1; - } - - if (si->tx_buff.len == 0) { - dev->stats.tx_packets++; - dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; - - /* We need to ensure that the transmitter has finished. */ - while ((stuart_readl(si, STLSR) & LSR_TEMT) == 0) - cpu_relax(); - si->last_clk = sched_clock(); - - /* - * Ok, we've finished transmitting. Now enable - * the receiver. Sometimes we get a receive IRQ - * immediately after a transmit... - */ - if (si->newspeed) { - pxa_irda_set_speed(si, si->newspeed); - si->newspeed = 0; - } else { - /* enable IR Receiver, disable IR Transmitter */ - stuart_writel(si, IrSR_IR_RECEIVE_ON | - IrSR_XMODE_PULSE_1_6, STISR); - /* enable STUART and receive interrupts */ - stuart_writel(si, IER_UUE | IER_RLSE | - IER_RAVIE | IER_RTIOE, STIER); - } - /* I'm hungry! */ - netif_wake_queue(dev); - } - break; - } - - return IRQ_HANDLED; -} - -/* FIR Receive DMA interrupt handler */ -static void pxa_irda_fir_dma_rx_irq(void *data) -{ - struct net_device *dev = data; - struct pxa_irda *si = netdev_priv(dev); - - dmaengine_terminate_all(si->rxdma); - netdev_dbg(dev, "pxa_ir: fir rx dma bus error\n"); -} - -/* FIR Transmit DMA interrupt handler */ -static void pxa_irda_fir_dma_tx_irq(void *data) -{ - struct net_device *dev = data; - struct pxa_irda *si = netdev_priv(dev); - - dmaengine_terminate_all(si->txdma); - if (dmaengine_tx_status(si->txdma, si->tx_cookie, NULL) == DMA_ERROR) { - dev->stats.tx_errors++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += si->dma_tx_buff_len; - } - - while (ficp_readl(si, ICSR1) & ICSR1_TBY) - cpu_relax(); - si->last_clk = sched_clock(); - - /* - * HACK: It looks like the TBY bit is dropped too soon. - * Without this delay things break. - */ - udelay(120); - - if (si->newspeed) { - pxa_irda_set_speed(si, si->newspeed); - si->newspeed = 0; - } else { - int i = 64; - - ficp_writel(si, 0, ICCR0); - pxa_irda_fir_dma_rx_start(si); - while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--) - ficp_readl(si, ICDR); - ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); - - if (i < 0) - printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n"); - } - netif_wake_queue(dev); -} - -/* EIF(Error in FIFO/End in Frame) handler for FIR */ -static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, int icsr0) -{ - unsigned int len, stat, data; - struct dma_tx_state state; - - /* Get the current data position. */ - - dmaengine_tx_status(si->rxdma, si->rx_cookie, &state); - len = IRDA_FRAME_SIZE_LIMIT - state.residue; - - do { - /* Read Status, and then Data. */ - stat = ficp_readl(si, ICSR1); - rmb(); - data = ficp_readl(si, ICDR); - - if (stat & (ICSR1_CRE | ICSR1_ROR)) { - dev->stats.rx_errors++; - if (stat & ICSR1_CRE) { - printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); - dev->stats.rx_crc_errors++; - } - if (stat & ICSR1_ROR) { - printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); - dev->stats.rx_over_errors++; - } - } else { - si->dma_rx_buff[len++] = data; - } - /* If we hit the end of frame, there's no point in continuing. */ - if (stat & ICSR1_EOF) - break; - } while (ficp_readl(si, ICSR0) & ICSR0_EIF); - - if (stat & ICSR1_EOF) { - /* end of frame. */ - struct sk_buff *skb; - - if (icsr0 & ICSR0_FRE) { - printk(KERN_ERR "pxa_ir: dropping erroneous frame\n"); - dev->stats.rx_dropped++; - return; - } - - skb = alloc_skb(len+1,GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); - dev->stats.rx_dropped++; - return; - } - - /* Align IP header to 20 bytes */ - skb_reserve(skb, 1); - skb_copy_to_linear_data(skb, si->dma_rx_buff, len); - skb_put(skb, len); - - /* Feed it to IrLAP */ - skb->dev = dev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; - } -} - -/* FIR interrupt handler */ -static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct pxa_irda *si = netdev_priv(dev); - int icsr0, i = 64; - - /* stop RX DMA */ - dmaengine_terminate_all(si->rxdma); - si->last_clk = sched_clock(); - icsr0 = ficp_readl(si, ICSR0); - - if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { - if (icsr0 & ICSR0_FRE) { - printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); - dev->stats.rx_frame_errors++; - } else { - printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); - dev->stats.rx_errors++; - } - ficp_writel(si, icsr0 & (ICSR0_FRE | ICSR0_RAB), ICSR0); - } - - if (icsr0 & ICSR0_EIF) { - /* An error in FIFO occurred, or there is a end of frame */ - pxa_irda_fir_irq_eif(si, dev, icsr0); - } - - ficp_writel(si, 0, ICCR0); - pxa_irda_fir_dma_rx_start(si); - while ((ficp_readl(si, ICSR1) & ICSR1_RNE) && i--) - ficp_readl(si, ICDR); - ficp_writel(si, ICCR0_ITR | ICCR0_RXE, ICCR0); - - if (i < 0) - printk(KERN_ERR "pxa_ir: cannot clear Rx FIFO!\n"); - - return IRQ_HANDLED; -} - -/* hard_xmit interface of irda device */ -static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct pxa_irda *si = netdev_priv(dev); - int speed = irda_get_next_speed(skb); - - /* - * Does this packet contain a request to change the interface - * speed? If so, remember it until we complete the transmission - * of this frame. - */ - if (speed != si->speed && speed != -1) - si->newspeed = speed; - - /* - * If this is an empty frame, we can bypass a lot. - */ - if (skb->len == 0) { - if (si->newspeed) { - si->newspeed = 0; - pxa_irda_set_speed(si, speed); - } - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - netif_stop_queue(dev); - - if (!IS_FIR(si)) { - si->tx_buff.data = si->tx_buff.head; - si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize); - - /* Disable STUART interrupts and switch to transmit mode. */ - stuart_writel(si, 0, STIER); - stuart_writel(si, IrSR_IR_TRANSMIT_ON | IrSR_XMODE_PULSE_1_6, - STISR); - - /* enable STUART and transmit interrupts */ - stuart_writel(si, IER_UUE | IER_TIE, STIER); - } else { - unsigned long mtt = irda_get_mtt(skb); - - si->dma_tx_buff_len = skb->len; - skb_copy_from_linear_data(skb, si->dma_tx_buff, skb->len); - - if (mtt) - while ((sched_clock() - si->last_clk) * 1000 < mtt) - cpu_relax(); - - /* stop RX DMA, disable FICP */ - dmaengine_terminate_all(si->rxdma); - ficp_writel(si, 0, ICCR0); - - pxa_irda_fir_dma_tx_start(si); - ficp_writel(si, ICCR0_ITR | ICCR0_TXE, ICCR0); - } - - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) -{ - struct if_irda_req *rq = (struct if_irda_req *)ifreq; - struct pxa_irda *si = netdev_priv(dev); - int ret; - - switch (cmd) { - case SIOCSBANDWIDTH: - ret = -EPERM; - if (capable(CAP_NET_ADMIN)) { - /* - * We are unable to set the speed if the - * device is not running. - */ - if (netif_running(dev)) { - ret = pxa_irda_set_speed(si, - rq->ifr_baudrate); - } else { - printk(KERN_INFO "pxa_ir: SIOCSBANDWIDTH: !netif_running\n"); - ret = 0; - } - } - break; - - case SIOCSMEDIABUSY: - ret = -EPERM; - if (capable(CAP_NET_ADMIN)) { - irda_device_set_media_busy(dev, TRUE); - ret = 0; - } - break; - - case SIOCGRECEIVING: - ret = 0; - rq->ifr_receiving = IS_FIR(si) ? 0 - : si->rx_buff.state != OUTSIDE_FRAME; - break; - - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - -static void pxa_irda_startup(struct pxa_irda *si) -{ - /* Disable STUART interrupts */ - stuart_writel(si, 0, STIER); - /* enable STUART interrupt to the processor */ - stuart_writel(si, MCR_OUT2, STMCR); - /* configure SIR frame format: StartBit - Data 7 ... Data 0 - Stop Bit */ - stuart_writel(si, LCR_WLS0 | LCR_WLS1, STLCR); - /* enable FIFO, we use FIFO to improve performance */ - stuart_writel(si, FCR_TRFIFOE | FCR_ITL_32, STFCR); - - /* disable FICP */ - ficp_writel(si, 0, ICCR0); - /* configure FICP ICCR2 */ - ficp_writel(si, ICCR2_TXP | ICCR2_TRIG_32, ICCR2); - - /* force SIR reinitialization */ - si->speed = 4000000; - pxa_irda_set_speed(si, 9600); - - printk(KERN_DEBUG "pxa_ir: irda startup\n"); -} - -static void pxa_irda_shutdown(struct pxa_irda *si) -{ - unsigned long flags; - - local_irq_save(flags); - - /* disable STUART and interrupt */ - stuart_writel(si, 0, STIER); - /* disable STUART SIR mode */ - stuart_writel(si, 0, STISR); - - /* disable DMA */ - dmaengine_terminate_all(si->rxdma); - dmaengine_terminate_all(si->txdma); - /* disable FICP */ - ficp_writel(si, 0, ICCR0); - - /* disable the STUART or FICP clocks */ - pxa_irda_disable_clk(si); - - local_irq_restore(flags); - - /* power off board transceiver */ - pxa_irda_set_mode(si, IR_OFF); - - printk(KERN_DEBUG "pxa_ir: irda shutdown\n"); -} - -static int pxa_irda_start(struct net_device *dev) -{ - struct pxa_irda *si = netdev_priv(dev); - dma_cap_mask_t mask; - struct dma_slave_config config; - struct pxad_param param; - int err; - - si->speed = 9600; - - err = request_irq(si->uart_irq, pxa_irda_sir_irq, 0, dev->name, dev); - if (err) - goto err_irq1; - - err = request_irq(si->icp_irq, pxa_irda_fir_irq, 0, dev->name, dev); - if (err) - goto err_irq2; - - /* - * The interrupt must remain disabled for now. - */ - disable_irq(si->uart_irq); - disable_irq(si->icp_irq); - - err = -EBUSY; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - param.prio = PXAD_PRIO_LOWEST; - - memset(&config, 0, sizeof(config)); - config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - config.src_addr = (dma_addr_t)si->irda_base + ICDR; - config.dst_addr = (dma_addr_t)si->irda_base + ICDR; - config.src_maxburst = 32; - config.dst_maxburst = 32; - - param.drcmr = si->drcmr_rx; - si->rxdma = dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, "rx"); - if (!si->rxdma) - goto err_rx_dma; - - param.drcmr = si->drcmr_tx; - si->txdma = dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, "tx"); - if (!si->txdma) - goto err_tx_dma; - - err = dmaengine_slave_config(si->rxdma, &config); - if (err) - goto err_dma_rx_buff; - err = dmaengine_slave_config(si->txdma, &config); - if (err) - goto err_dma_rx_buff; - - err = -ENOMEM; - si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, - &si->dma_rx_buff_phy, GFP_KERNEL); - if (!si->dma_rx_buff) - goto err_dma_rx_buff; - - si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, - &si->dma_tx_buff_phy, GFP_KERNEL); - if (!si->dma_tx_buff) - goto err_dma_tx_buff; - - /* Setup the serial port for the initial speed. */ - pxa_irda_startup(si); - - /* - * Open a new IrLAP layer instance. - */ - si->irlap = irlap_open(dev, &si->qos, "pxa"); - err = -ENOMEM; - if (!si->irlap) - goto err_irlap; - - /* - * Now enable the interrupt and start the queue - */ - enable_irq(si->uart_irq); - enable_irq(si->icp_irq); - netif_start_queue(dev); - - printk(KERN_DEBUG "pxa_ir: irda driver opened\n"); - - return 0; - -err_irlap: - pxa_irda_shutdown(si); - dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); -err_dma_tx_buff: - dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); -err_dma_rx_buff: - dma_release_channel(si->txdma); -err_tx_dma: - dma_release_channel(si->rxdma); -err_rx_dma: - free_irq(si->icp_irq, dev); -err_irq2: - free_irq(si->uart_irq, dev); -err_irq1: - - return err; -} - -static int pxa_irda_stop(struct net_device *dev) -{ - struct pxa_irda *si = netdev_priv(dev); - - netif_stop_queue(dev); - - pxa_irda_shutdown(si); - - /* Stop IrLAP */ - if (si->irlap) { - irlap_close(si->irlap); - si->irlap = NULL; - } - - free_irq(si->uart_irq, dev); - free_irq(si->icp_irq, dev); - - dmaengine_terminate_all(si->rxdma); - dmaengine_terminate_all(si->txdma); - dma_release_channel(si->rxdma); - dma_release_channel(si->txdma); - - if (si->dma_rx_buff) - dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_tx_buff, si->dma_tx_buff_phy); - if (si->dma_tx_buff) - dma_free_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT, si->dma_rx_buff, si->dma_rx_buff_phy); - - printk(KERN_DEBUG "pxa_ir: irda driver closed\n"); - return 0; -} - -static int pxa_irda_suspend(struct platform_device *_dev, pm_message_t state) -{ - struct net_device *dev = platform_get_drvdata(_dev); - struct pxa_irda *si; - - if (dev && netif_running(dev)) { - si = netdev_priv(dev); - netif_device_detach(dev); - pxa_irda_shutdown(si); - } - - return 0; -} - -static int pxa_irda_resume(struct platform_device *_dev) -{ - struct net_device *dev = platform_get_drvdata(_dev); - struct pxa_irda *si; - - if (dev && netif_running(dev)) { - si = netdev_priv(dev); - pxa_irda_startup(si); - netif_device_attach(dev); - netif_wake_queue(dev); - } - - return 0; -} - - -static int pxa_irda_init_iobuf(iobuff_t *io, int size) -{ - io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); - if (io->head != NULL) { - io->truesize = size; - io->in_frame = FALSE; - io->state = OUTSIDE_FRAME; - io->data = io->head; - } - return io->head ? 0 : -ENOMEM; -} - -static const struct net_device_ops pxa_irda_netdev_ops = { - .ndo_open = pxa_irda_start, - .ndo_stop = pxa_irda_stop, - .ndo_start_xmit = pxa_irda_hard_xmit, - .ndo_do_ioctl = pxa_irda_ioctl, -}; - -static int pxa_irda_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct resource *res; - struct pxa_irda *si; - void __iomem *ficp, *stuart; - unsigned int baudrate_mask; - int err; - - if (!pdev->dev.platform_data) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ficp = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ficp)) { - dev_err(&pdev->dev, "resource ficp not defined\n"); - return PTR_ERR(ficp); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - stuart = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(stuart)) { - dev_err(&pdev->dev, "resource stuart not defined\n"); - return PTR_ERR(stuart); - } - - dev = alloc_irdadev(sizeof(struct pxa_irda)); - if (!dev) { - err = -ENOMEM; - goto err_mem_1; - } - - SET_NETDEV_DEV(dev, &pdev->dev); - si = netdev_priv(dev); - si->dev = &pdev->dev; - si->pdata = pdev->dev.platform_data; - - si->irda_base = ficp; - si->stuart_base = stuart; - si->uart_irq = platform_get_irq(pdev, 0); - si->icp_irq = platform_get_irq(pdev, 1); - - si->sir_clk = devm_clk_get(&pdev->dev, "UARTCLK"); - si->fir_clk = devm_clk_get(&pdev->dev, "FICPCLK"); - if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) { - err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk); - goto err_mem_4; - } - - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (res) - si->drcmr_rx = res->start; - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (res) - si->drcmr_tx = res->start; - - /* - * Initialise the SIR buffers - */ - err = pxa_irda_init_iobuf(&si->rx_buff, 14384); - if (err) - goto err_mem_4; - err = pxa_irda_init_iobuf(&si->tx_buff, 4000); - if (err) - goto err_mem_5; - - if (gpio_is_valid(si->pdata->gpio_pwdown)) { - err = gpio_request(si->pdata->gpio_pwdown, "IrDA switch"); - if (err) - goto err_startup; - err = gpio_direction_output(si->pdata->gpio_pwdown, - !si->pdata->gpio_pwdown_inverted); - if (err) { - gpio_free(si->pdata->gpio_pwdown); - goto err_startup; - } - } - - if (si->pdata->startup) { - err = si->pdata->startup(si->dev); - if (err) - goto err_startup; - } - - if (gpio_is_valid(si->pdata->gpio_pwdown) && si->pdata->startup) - dev_warn(si->dev, "gpio_pwdown and startup() both defined!\n"); - - dev->netdev_ops = &pxa_irda_netdev_ops; - - irda_init_max_qos_capabilies(&si->qos); - - baudrate_mask = 0; - if (si->pdata->transceiver_cap & IR_SIRMODE) - baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - if (si->pdata->transceiver_cap & IR_FIRMODE) - baudrate_mask |= IR_4000000 << 8; - - si->qos.baud_rate.bits &= baudrate_mask; - si->qos.min_turn_time.bits = 7; /* 1ms or more */ - - irda_qos_bits_to_value(&si->qos); - - err = register_netdev(dev); - - if (err == 0) - platform_set_drvdata(pdev, dev); - - if (err) { - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); -err_startup: - kfree(si->tx_buff.head); -err_mem_5: - kfree(si->rx_buff.head); -err_mem_4: - free_netdev(dev); - } -err_mem_1: - return err; -} - -static int pxa_irda_remove(struct platform_device *_dev) -{ - struct net_device *dev = platform_get_drvdata(_dev); - - if (dev) { - struct pxa_irda *si = netdev_priv(dev); - unregister_netdev(dev); - if (gpio_is_valid(si->pdata->gpio_pwdown)) - gpio_free(si->pdata->gpio_pwdown); - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); - kfree(si->tx_buff.head); - kfree(si->rx_buff.head); - free_netdev(dev); - } - - return 0; -} - -static struct platform_driver pxa_ir_driver = { - .driver = { - .name = "pxa2xx-ir", - }, - .probe = pxa_irda_probe, - .remove = pxa_irda_remove, - .suspend = pxa_irda_suspend, - .resume = pxa_irda_resume, -}; - -module_platform_driver(pxa_ir_driver); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-ir"); diff --git a/drivers/staging/irda/drivers/sa1100_ir.c b/drivers/staging/irda/drivers/sa1100_ir.c deleted file mode 100644 index b6e44ff4e373..000000000000 --- a/drivers/staging/irda/drivers/sa1100_ir.c +++ /dev/null @@ -1,1150 +0,0 @@ -/* - * linux/drivers/net/irda/sa1100_ir.c - * - * Copyright (C) 2000-2001 Russell King - * - * 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. - * - * Infra-red driver for the StrongARM SA1100 embedded microprocessor - * - * Note that we don't have to worry about the SA1111's DMA bugs in here, - * so we use the straight forward dma_map_* functions with a null pointer. - * - * This driver takes one kernel command line parameter, sa1100ir=, with - * the following options: - * max_rate:baudrate - set the maximum baud rate - * power_level:level - set the transmitter power level - * tx_lpm:0|1 - set transmit low power mode - */ -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/rtnetlink.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/dmaengine.h> -#include <linux/sa11x0-dma.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/irda_device.h> - -#include <mach/hardware.h> -#include <linux/platform_data/irda-sa11x0.h> - -static int power_level = 3; -static int tx_lpm; -static int max_rate = 4000000; - -struct sa1100_buf { - struct device *dev; - struct sk_buff *skb; - struct scatterlist sg; - struct dma_chan *chan; - dma_cookie_t cookie; -}; - -struct sa1100_irda { - unsigned char utcr4; - unsigned char power; - unsigned char open; - - int speed; - int newspeed; - - struct sa1100_buf dma_rx; - struct sa1100_buf dma_tx; - - struct device *dev; - struct irda_platform_data *pdata; - struct irlap_cb *irlap; - struct qos_info qos; - - iobuff_t tx_buff; - iobuff_t rx_buff; - - int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *); - irqreturn_t (*irq)(struct net_device *, struct sa1100_irda *); -}; - -static int sa1100_irda_set_speed(struct sa1100_irda *, int); - -#define IS_FIR(si) ((si)->speed >= 4000000) - -#define HPSIR_MAX_RXLEN 2047 - -static struct dma_slave_config sa1100_irda_sir_tx = { - .direction = DMA_TO_DEVICE, - .dst_addr = __PREG(Ser2UTDR), - .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, - .dst_maxburst = 4, -}; - -static struct dma_slave_config sa1100_irda_fir_rx = { - .direction = DMA_FROM_DEVICE, - .src_addr = __PREG(Ser2HSDR), - .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, - .src_maxburst = 8, -}; - -static struct dma_slave_config sa1100_irda_fir_tx = { - .direction = DMA_TO_DEVICE, - .dst_addr = __PREG(Ser2HSDR), - .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, - .dst_maxburst = 8, -}; - -static unsigned sa1100_irda_dma_xferred(struct sa1100_buf *buf) -{ - struct dma_chan *chan = buf->chan; - struct dma_tx_state state; - enum dma_status status; - - status = chan->device->device_tx_status(chan, buf->cookie, &state); - if (status != DMA_PAUSED) - return 0; - - return sg_dma_len(&buf->sg) - state.residue; -} - -static int sa1100_irda_dma_request(struct device *dev, struct sa1100_buf *buf, - const char *name, struct dma_slave_config *cfg) -{ - dma_cap_mask_t m; - int ret; - - dma_cap_zero(m); - dma_cap_set(DMA_SLAVE, m); - - buf->chan = dma_request_channel(m, sa11x0_dma_filter_fn, (void *)name); - if (!buf->chan) { - dev_err(dev, "unable to request DMA channel for %s\n", - name); - return -ENOENT; - } - - ret = dmaengine_slave_config(buf->chan, cfg); - if (ret) - dev_warn(dev, "DMA slave_config for %s returned %d\n", - name, ret); - - buf->dev = buf->chan->device->dev; - - return 0; -} - -static void sa1100_irda_dma_start(struct sa1100_buf *buf, - enum dma_transfer_direction dir, dma_async_tx_callback cb, void *cb_p) -{ - struct dma_async_tx_descriptor *desc; - struct dma_chan *chan = buf->chan; - - desc = dmaengine_prep_slave_sg(chan, &buf->sg, 1, dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (desc) { - desc->callback = cb; - desc->callback_param = cb_p; - buf->cookie = dmaengine_submit(desc); - dma_async_issue_pending(chan); - } -} - -/* - * Allocate and map the receive buffer, unless it is already allocated. - */ -static int sa1100_irda_rx_alloc(struct sa1100_irda *si) -{ - if (si->dma_rx.skb) - return 0; - - si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); - if (!si->dma_rx.skb) { - printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n"); - return -ENOMEM; - } - - /* - * Align any IP headers that may be contained - * within the frame. - */ - skb_reserve(si->dma_rx.skb, 1); - - sg_set_buf(&si->dma_rx.sg, si->dma_rx.skb->data, HPSIR_MAX_RXLEN); - if (dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE) == 0) { - dev_kfree_skb_any(si->dma_rx.skb); - return -ENOMEM; - } - - return 0; -} - -/* - * We want to get here as soon as possible, and get the receiver setup. - * We use the existing buffer. - */ -static void sa1100_irda_rx_dma_start(struct sa1100_irda *si) -{ - if (!si->dma_rx.skb) { - printk(KERN_ERR "sa1100_ir: rx buffer went missing\n"); - return; - } - - /* - * First empty receive FIFO - */ - Ser2HSCR0 = HSCR0_HSSP; - - /* - * Enable the DMA, receiver and receive interrupt. - */ - dmaengine_terminate_all(si->dma_rx.chan); - sa1100_irda_dma_start(&si->dma_rx, DMA_DEV_TO_MEM, NULL, NULL); - - Ser2HSCR0 = HSCR0_HSSP | HSCR0_RXE; -} - -static void sa1100_irda_check_speed(struct sa1100_irda *si) -{ - if (si->newspeed) { - sa1100_irda_set_speed(si, si->newspeed); - si->newspeed = 0; - } -} - -/* - * HP-SIR format support. - */ -static void sa1100_irda_sirtxdma_irq(void *id) -{ - struct net_device *dev = id; - struct sa1100_irda *si = netdev_priv(dev); - - dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE); - dev_kfree_skb(si->dma_tx.skb); - si->dma_tx.skb = NULL; - - dev->stats.tx_packets++; - dev->stats.tx_bytes += sg_dma_len(&si->dma_tx.sg); - - /* We need to ensure that the transmitter has finished. */ - do - rmb(); - while (Ser2UTSR1 & UTSR1_TBY); - - /* - * Ok, we've finished transmitting. Now enable the receiver. - * Sometimes we get a receive IRQ immediately after a transmit... - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; - - sa1100_irda_check_speed(si); - - /* I'm hungry! */ - netif_wake_queue(dev); -} - -static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev, - struct sa1100_irda *si) -{ - si->tx_buff.data = si->tx_buff.head; - si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, - si->tx_buff.truesize); - - si->dma_tx.skb = skb; - sg_set_buf(&si->dma_tx.sg, si->tx_buff.data, si->tx_buff.len); - if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { - si->dma_tx.skb = NULL; - netif_wake_queue(dev); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_sirtxdma_irq, dev); - - /* - * The mean turn-around time is enforced by XBOF padding, - * so we don't have to do anything special here. - */ - Ser2UTCR3 = UTCR3_TXE; - - return NETDEV_TX_OK; -} - -static irqreturn_t sa1100_irda_sir_irq(struct net_device *dev, struct sa1100_irda *si) -{ - int status; - - status = Ser2UTSR0; - - /* - * Deal with any receive errors first. The bytes in error may be - * the only bytes in the receive FIFO, so we do this first. - */ - while (status & UTSR0_EIF) { - int stat, data; - - stat = Ser2UTSR1; - data = Ser2UTDR; - - if (stat & (UTSR1_FRE | UTSR1_ROR)) { - dev->stats.rx_errors++; - if (stat & UTSR1_FRE) - dev->stats.rx_frame_errors++; - if (stat & UTSR1_ROR) - dev->stats.rx_fifo_errors++; - } else - async_unwrap_char(dev, &dev->stats, &si->rx_buff, data); - - status = Ser2UTSR0; - } - - /* - * We must clear certain bits. - */ - Ser2UTSR0 = status & (UTSR0_RID | UTSR0_RBB | UTSR0_REB); - - if (status & UTSR0_RFS) { - /* - * There are at least 4 bytes in the FIFO. Read 3 bytes - * and leave the rest to the block below. - */ - async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); - async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); - async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); - } - - if (status & (UTSR0_RFS | UTSR0_RID)) { - /* - * Fifo contains more than 1 character. - */ - do { - async_unwrap_char(dev, &dev->stats, &si->rx_buff, - Ser2UTDR); - } while (Ser2UTSR1 & UTSR1_RNE); - - } - - return IRQ_HANDLED; -} - -/* - * FIR format support. - */ -static void sa1100_irda_firtxdma_irq(void *id) -{ - struct net_device *dev = id; - struct sa1100_irda *si = netdev_priv(dev); - struct sk_buff *skb; - - /* - * Wait for the transmission to complete. Unfortunately, - * the hardware doesn't give us an interrupt to indicate - * "end of frame". - */ - do - rmb(); - while (!(Ser2HSSR0 & HSSR0_TUR) || Ser2HSSR1 & HSSR1_TBY); - - /* - * Clear the transmit underrun bit. - */ - Ser2HSSR0 = HSSR0_TUR; - - /* - * Do we need to change speed? Note that we're lazy - * here - we don't free the old dma_rx.skb. We don't need - * to allocate a buffer either. - */ - sa1100_irda_check_speed(si); - - /* - * Start reception. This disables the transmitter for - * us. This will be using the existing RX buffer. - */ - sa1100_irda_rx_dma_start(si); - - /* Account and free the packet. */ - skb = si->dma_tx.skb; - if (skb) { - dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, - DMA_TO_DEVICE); - dev->stats.tx_packets ++; - dev->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - si->dma_tx.skb = NULL; - } - - /* - * Make sure that the TX queue is available for sending - * (for retries). TX has priority over RX at all times. - */ - netif_wake_queue(dev); -} - -static int sa1100_irda_fir_tx_start(struct sk_buff *skb, struct net_device *dev, - struct sa1100_irda *si) -{ - int mtt = irda_get_mtt(skb); - - si->dma_tx.skb = skb; - sg_set_buf(&si->dma_tx.sg, skb->data, skb->len); - if (dma_map_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, DMA_TO_DEVICE) == 0) { - si->dma_tx.skb = NULL; - netif_wake_queue(dev); - dev->stats.tx_dropped++; - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - sa1100_irda_dma_start(&si->dma_tx, DMA_MEM_TO_DEV, sa1100_irda_firtxdma_irq, dev); - - /* - * If we have a mean turn-around time, impose the specified - * specified delay. We could shorten this by timing from - * the point we received the packet. - */ - if (mtt) - udelay(mtt); - - Ser2HSCR0 = HSCR0_HSSP | HSCR0_TXE; - - return NETDEV_TX_OK; -} - -static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev) -{ - struct sk_buff *skb = si->dma_rx.skb; - unsigned int len, stat, data; - - if (!skb) { - printk(KERN_ERR "sa1100_ir: SKB is NULL!\n"); - return; - } - - /* - * Get the current data position. - */ - len = sa1100_irda_dma_xferred(&si->dma_rx); - if (len > HPSIR_MAX_RXLEN) - len = HPSIR_MAX_RXLEN; - dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); - - do { - /* - * Read Status, and then Data. - */ - stat = Ser2HSSR1; - rmb(); - data = Ser2HSDR; - - if (stat & (HSSR1_CRE | HSSR1_ROR)) { - dev->stats.rx_errors++; - if (stat & HSSR1_CRE) - dev->stats.rx_crc_errors++; - if (stat & HSSR1_ROR) - dev->stats.rx_frame_errors++; - } else - skb->data[len++] = data; - - /* - * If we hit the end of frame, there's - * no point in continuing. - */ - if (stat & HSSR1_EOF) - break; - } while (Ser2HSSR0 & HSSR0_EIF); - - if (stat & HSSR1_EOF) { - si->dma_rx.skb = NULL; - - skb_put(skb, len); - skb->dev = dev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - dev->stats.rx_packets++; - dev->stats.rx_bytes += len; - - /* - * Before we pass the buffer up, allocate a new one. - */ - sa1100_irda_rx_alloc(si); - - netif_rx(skb); - } else { - /* - * Remap the buffer - it was previously mapped, and we - * hope that this succeeds. - */ - dma_map_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, DMA_FROM_DEVICE); - } -} - -/* - * We only have to handle RX events here; transmit events go via the TX - * DMA handler. We disable RX, process, and the restart RX. - */ -static irqreturn_t sa1100_irda_fir_irq(struct net_device *dev, struct sa1100_irda *si) -{ - /* - * Stop RX DMA - */ - dmaengine_pause(si->dma_rx.chan); - - /* - * Framing error - we throw away the packet completely. - * Clearing RXE flushes the error conditions and data - * from the fifo. - */ - if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) { - dev->stats.rx_errors++; - - if (Ser2HSSR0 & HSSR0_FRE) - dev->stats.rx_frame_errors++; - - /* - * Clear out the DMA... - */ - Ser2HSCR0 = HSCR0_HSSP; - - /* - * Clear selected status bits now, so we - * don't miss them next time around. - */ - Ser2HSSR0 = HSSR0_FRE | HSSR0_RAB; - } - - /* - * Deal with any receive errors. The any of the lowest - * 8 bytes in the FIFO may contain an error. We must read - * them one by one. The "error" could even be the end of - * packet! - */ - if (Ser2HSSR0 & HSSR0_EIF) - sa1100_irda_fir_error(si, dev); - - /* - * No matter what happens, we must restart reception. - */ - sa1100_irda_rx_dma_start(si); - - return IRQ_HANDLED; -} - -/* - * Set the IrDA communications speed. - */ -static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed) -{ - unsigned long flags; - int brd, ret = -EINVAL; - - switch (speed) { - case 9600: case 19200: case 38400: - case 57600: case 115200: - brd = 3686400 / (16 * speed) - 1; - - /* Stop the receive DMA, and configure transmit. */ - if (IS_FIR(si)) { - dmaengine_terminate_all(si->dma_rx.chan); - dmaengine_slave_config(si->dma_tx.chan, - &sa1100_irda_sir_tx); - } - - local_irq_save(flags); - - Ser2UTCR3 = 0; - Ser2HSCR0 = HSCR0_UART; - - Ser2UTCR1 = brd >> 8; - Ser2UTCR2 = brd; - - /* - * Clear status register - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE; - - if (si->pdata->set_speed) - si->pdata->set_speed(si->dev, speed); - - si->speed = speed; - si->tx_start = sa1100_irda_sir_tx_start; - si->irq = sa1100_irda_sir_irq; - - local_irq_restore(flags); - ret = 0; - break; - - case 4000000: - if (!IS_FIR(si)) - dmaengine_slave_config(si->dma_tx.chan, - &sa1100_irda_fir_tx); - - local_irq_save(flags); - - Ser2HSSR0 = 0xff; - Ser2HSCR0 = HSCR0_HSSP; - Ser2UTCR3 = 0; - - si->speed = speed; - si->tx_start = sa1100_irda_fir_tx_start; - si->irq = sa1100_irda_fir_irq; - - if (si->pdata->set_speed) - si->pdata->set_speed(si->dev, speed); - - sa1100_irda_rx_alloc(si); - sa1100_irda_rx_dma_start(si); - - local_irq_restore(flags); - - break; - - default: - break; - } - - return ret; -} - -/* - * Control the power state of the IrDA transmitter. - * State: - * 0 - off - * 1 - short range, lowest power - * 2 - medium range, medium power - * 3 - maximum range, high power - * - * Currently, only assabet is known to support this. - */ -static int -__sa1100_irda_set_power(struct sa1100_irda *si, unsigned int state) -{ - int ret = 0; - if (si->pdata->set_power) - ret = si->pdata->set_power(si->dev, state); - return ret; -} - -static inline int -sa1100_set_power(struct sa1100_irda *si, unsigned int state) -{ - int ret; - - ret = __sa1100_irda_set_power(si, state); - if (ret == 0) - si->power = state; - - return ret; -} - -static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct sa1100_irda *si = netdev_priv(dev); - - return si->irq(dev, si); -} - -static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct sa1100_irda *si = netdev_priv(dev); - int speed = irda_get_next_speed(skb); - - /* - * Does this packet contain a request to change the interface - * speed? If so, remember it until we complete the transmission - * of this frame. - */ - if (speed != si->speed && speed != -1) - si->newspeed = speed; - - /* If this is an empty frame, we can bypass a lot. */ - if (skb->len == 0) { - sa1100_irda_check_speed(si); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - netif_stop_queue(dev); - - /* We must not already have a skb to transmit... */ - BUG_ON(si->dma_tx.skb); - - return si->tx_start(skb, dev, si); -} - -static int -sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) -{ - struct if_irda_req *rq = (struct if_irda_req *)ifreq; - struct sa1100_irda *si = netdev_priv(dev); - int ret = -EOPNOTSUPP; - - switch (cmd) { - case SIOCSBANDWIDTH: - if (capable(CAP_NET_ADMIN)) { - /* - * We are unable to set the speed if the - * device is not running. - */ - if (si->open) { - ret = sa1100_irda_set_speed(si, - rq->ifr_baudrate); - } else { - printk("sa1100_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n"); - ret = 0; - } - } - break; - - case SIOCSMEDIABUSY: - ret = -EPERM; - if (capable(CAP_NET_ADMIN)) { - irda_device_set_media_busy(dev, TRUE); - ret = 0; - } - break; - - case SIOCGRECEIVING: - rq->ifr_receiving = IS_FIR(si) ? 0 - : si->rx_buff.state != OUTSIDE_FRAME; - break; - - default: - break; - } - - return ret; -} - -static int sa1100_irda_startup(struct sa1100_irda *si) -{ - int ret; - - /* - * Ensure that the ports for this device are setup correctly. - */ - if (si->pdata->startup) { - ret = si->pdata->startup(si->dev); - if (ret) - return ret; - } - - /* - * Configure PPC for IRDA - we want to drive TXD2 low. - * We also want to drive this pin low during sleep. - */ - PPSR &= ~PPC_TXD2; - PSDR &= ~PPC_TXD2; - PPDR |= PPC_TXD2; - - /* - * Enable HP-SIR modulation, and ensure that the port is disabled. - */ - Ser2UTCR3 = 0; - Ser2HSCR0 = HSCR0_UART; - Ser2UTCR4 = si->utcr4; - Ser2UTCR0 = UTCR0_8BitData; - Ser2HSCR2 = HSCR2_TrDataH | HSCR2_RcDataL; - - /* - * Clear status register - */ - Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID; - - ret = sa1100_irda_set_speed(si, si->speed = 9600); - if (ret) { - Ser2UTCR3 = 0; - Ser2HSCR0 = 0; - - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); - } - - return ret; -} - -static void sa1100_irda_shutdown(struct sa1100_irda *si) -{ - /* - * Stop all DMA activity. - */ - dmaengine_terminate_all(si->dma_rx.chan); - dmaengine_terminate_all(si->dma_tx.chan); - - /* Disable the port. */ - Ser2UTCR3 = 0; - Ser2HSCR0 = 0; - - if (si->pdata->shutdown) - si->pdata->shutdown(si->dev); -} - -static int sa1100_irda_start(struct net_device *dev) -{ - struct sa1100_irda *si = netdev_priv(dev); - int err; - - si->speed = 9600; - - err = sa1100_irda_dma_request(si->dev, &si->dma_rx, "Ser2ICPRc", - &sa1100_irda_fir_rx); - if (err) - goto err_rx_dma; - - err = sa1100_irda_dma_request(si->dev, &si->dma_tx, "Ser2ICPTr", - &sa1100_irda_sir_tx); - if (err) - goto err_tx_dma; - - /* - * Setup the serial port for the specified speed. - */ - err = sa1100_irda_startup(si); - if (err) - goto err_startup; - - /* - * Open a new IrLAP layer instance. - */ - si->irlap = irlap_open(dev, &si->qos, "sa1100"); - err = -ENOMEM; - if (!si->irlap) - goto err_irlap; - - err = request_irq(dev->irq, sa1100_irda_irq, 0, dev->name, dev); - if (err) - goto err_irq; - - /* - * Now enable the interrupt and start the queue - */ - si->open = 1; - sa1100_set_power(si, power_level); /* low power mode */ - - netif_start_queue(dev); - return 0; - -err_irq: - irlap_close(si->irlap); -err_irlap: - si->open = 0; - sa1100_irda_shutdown(si); -err_startup: - dma_release_channel(si->dma_tx.chan); -err_tx_dma: - dma_release_channel(si->dma_rx.chan); -err_rx_dma: - return err; -} - -static int sa1100_irda_stop(struct net_device *dev) -{ - struct sa1100_irda *si = netdev_priv(dev); - struct sk_buff *skb; - - netif_stop_queue(dev); - - si->open = 0; - sa1100_irda_shutdown(si); - - /* - * If we have been doing any DMA activity, make sure we - * tidy that up cleanly. - */ - skb = si->dma_rx.skb; - if (skb) { - dma_unmap_sg(si->dma_rx.dev, &si->dma_rx.sg, 1, - DMA_FROM_DEVICE); - dev_kfree_skb(skb); - si->dma_rx.skb = NULL; - } - - skb = si->dma_tx.skb; - if (skb) { - dma_unmap_sg(si->dma_tx.dev, &si->dma_tx.sg, 1, - DMA_TO_DEVICE); - dev_kfree_skb(skb); - si->dma_tx.skb = NULL; - } - - /* Stop IrLAP */ - if (si->irlap) { - irlap_close(si->irlap); - si->irlap = NULL; - } - - /* - * Free resources - */ - dma_release_channel(si->dma_tx.chan); - dma_release_channel(si->dma_rx.chan); - free_irq(dev->irq, dev); - - sa1100_set_power(si, 0); - - return 0; -} - -static int sa1100_irda_init_iobuf(iobuff_t *io, int size) -{ - io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); - if (io->head != NULL) { - io->truesize = size; - io->in_frame = FALSE; - io->state = OUTSIDE_FRAME; - io->data = io->head; - } - return io->head ? 0 : -ENOMEM; -} - -static const struct net_device_ops sa1100_irda_netdev_ops = { - .ndo_open = sa1100_irda_start, - .ndo_stop = sa1100_irda_stop, - .ndo_start_xmit = sa1100_irda_hard_xmit, - .ndo_do_ioctl = sa1100_irda_ioctl, -}; - -static int sa1100_irda_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct sa1100_irda *si; - unsigned int baudrate_mask; - int err, irq; - - if (!pdev->dev.platform_data) - return -EINVAL; - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return irq < 0 ? irq : -ENXIO; - - err = request_mem_region(__PREG(Ser2UTCR0), 0x24, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_1; - err = request_mem_region(__PREG(Ser2HSCR0), 0x1c, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_2; - err = request_mem_region(__PREG(Ser2HSCR2), 0x04, "IrDA") ? 0 : -EBUSY; - if (err) - goto err_mem_3; - - dev = alloc_irdadev(sizeof(struct sa1100_irda)); - if (!dev) { - err = -ENOMEM; - goto err_mem_4; - } - - SET_NETDEV_DEV(dev, &pdev->dev); - - si = netdev_priv(dev); - si->dev = &pdev->dev; - si->pdata = pdev->dev.platform_data; - - sg_init_table(&si->dma_rx.sg, 1); - sg_init_table(&si->dma_tx.sg, 1); - - /* - * Initialise the HP-SIR buffers - */ - err = sa1100_irda_init_iobuf(&si->rx_buff, 14384); - if (err) - goto err_mem_5; - err = sa1100_irda_init_iobuf(&si->tx_buff, IRDA_SIR_MAX_FRAME); - if (err) - goto err_mem_5; - - dev->netdev_ops = &sa1100_irda_netdev_ops; - dev->irq = irq; - - irda_init_max_qos_capabilies(&si->qos); - - /* - * We support original IRDA up to 115k2. (we don't currently - * support 4Mbps). Min Turn Time set to 1ms or greater. - */ - baudrate_mask = IR_9600; - - switch (max_rate) { - case 4000000: baudrate_mask |= IR_4000000 << 8; - case 115200: baudrate_mask |= IR_115200; - case 57600: baudrate_mask |= IR_57600; - case 38400: baudrate_mask |= IR_38400; - case 19200: baudrate_mask |= IR_19200; - } - - si->qos.baud_rate.bits &= baudrate_mask; - si->qos.min_turn_time.bits = 7; - - irda_qos_bits_to_value(&si->qos); - - si->utcr4 = UTCR4_HPSIR; - if (tx_lpm) - si->utcr4 |= UTCR4_Z1_6us; - - /* - * Initially enable HP-SIR modulation, and ensure that the port - * is disabled. - */ - Ser2UTCR3 = 0; - Ser2UTCR4 = si->utcr4; - Ser2HSCR0 = HSCR0_UART; - - err = register_netdev(dev); - if (err == 0) - platform_set_drvdata(pdev, dev); - - if (err) { - err_mem_5: - kfree(si->tx_buff.head); - kfree(si->rx_buff.head); - free_netdev(dev); - err_mem_4: - release_mem_region(__PREG(Ser2HSCR2), 0x04); - err_mem_3: - release_mem_region(__PREG(Ser2HSCR0), 0x1c); - err_mem_2: - release_mem_region(__PREG(Ser2UTCR0), 0x24); - } - err_mem_1: - return err; -} - -static int sa1100_irda_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - - if (dev) { - struct sa1100_irda *si = netdev_priv(dev); - unregister_netdev(dev); - kfree(si->tx_buff.head); - kfree(si->rx_buff.head); - free_netdev(dev); - } - - release_mem_region(__PREG(Ser2HSCR2), 0x04); - release_mem_region(__PREG(Ser2HSCR0), 0x1c); - release_mem_region(__PREG(Ser2UTCR0), 0x24); - - return 0; -} - -#ifdef CONFIG_PM -/* - * Suspend the IrDA interface. - */ -static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct sa1100_irda *si; - - if (!dev) - return 0; - - si = netdev_priv(dev); - if (si->open) { - /* - * Stop the transmit queue - */ - netif_device_detach(dev); - disable_irq(dev->irq); - sa1100_irda_shutdown(si); - __sa1100_irda_set_power(si, 0); - } - - return 0; -} - -/* - * Resume the IrDA interface. - */ -static int sa1100_irda_resume(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata(pdev); - struct sa1100_irda *si; - - if (!dev) - return 0; - - si = netdev_priv(dev); - if (si->open) { - /* - * If we missed a speed change, initialise at the new speed - * directly. It is debatable whether this is actually - * required, but in the interests of continuing from where - * we left off it is desirable. The converse argument is - * that we should re-negotiate at 9600 baud again. - */ - if (si->newspeed) { - si->speed = si->newspeed; - si->newspeed = 0; - } - - sa1100_irda_startup(si); - __sa1100_irda_set_power(si, si->power); - enable_irq(dev->irq); - - /* - * This automatically wakes up the queue - */ - netif_device_attach(dev); - } - - return 0; -} -#else -#define sa1100_irda_suspend NULL -#define sa1100_irda_resume NULL -#endif - -static struct platform_driver sa1100ir_driver = { - .probe = sa1100_irda_probe, - .remove = sa1100_irda_remove, - .suspend = sa1100_irda_suspend, - .resume = sa1100_irda_resume, - .driver = { - .name = "sa11x0-ir", - }, -}; - -static int __init sa1100_irda_init(void) -{ - /* - * Limit power level a sensible range. - */ - if (power_level < 1) - power_level = 1; - if (power_level > 3) - power_level = 3; - - return platform_driver_register(&sa1100ir_driver); -} - -static void __exit sa1100_irda_exit(void) -{ - platform_driver_unregister(&sa1100ir_driver); -} - -module_init(sa1100_irda_init); -module_exit(sa1100_irda_exit); -module_param(power_level, int, 0); -module_param(tx_lpm, int, 0); -module_param(max_rate, int, 0); - -MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); -MODULE_DESCRIPTION("StrongARM SA1100 IrDA driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(power_level, "IrDA power level, 1 (low) to 3 (high)"); -MODULE_PARM_DESC(tx_lpm, "Enable transmitter low power (1.6us) mode"); -MODULE_PARM_DESC(max_rate, "Maximum baud rate (4000000, 115200, 57600, 38400, 19200, 9600)"); -MODULE_ALIAS("platform:sa11x0-ir"); diff --git a/drivers/staging/irda/drivers/sh_sir.c b/drivers/staging/irda/drivers/sh_sir.c deleted file mode 100644 index 0d0687cc454a..000000000000 --- a/drivers/staging/irda/drivers/sh_sir.c +++ /dev/null @@ -1,810 +0,0 @@ -/* - * SuperH IrDA Driver - * - * Copyright (C) 2009 Renesas Solutions Corp. - * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * Based on bfin_sir.c - * Copyright 2006-2009 Analog Devices Inc. - * - * 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 <linux/io.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <net/irda/wrapper.h> -#include <net/irda/irda_device.h> -#include <asm/clock.h> - -#define DRIVER_NAME "sh_sir" - -#define RX_PHASE (1 << 0) -#define TX_PHASE (1 << 1) -#define TX_COMP_PHASE (1 << 2) /* tx complete */ -#define NONE_PHASE (1 << 31) - -#define IRIF_RINTCLR 0x0016 /* DMA rx interrupt source clear */ -#define IRIF_TINTCLR 0x0018 /* DMA tx interrupt source clear */ -#define IRIF_SIR0 0x0020 /* IrDA-SIR10 control */ -#define IRIF_SIR1 0x0022 /* IrDA-SIR10 baudrate error correction */ -#define IRIF_SIR2 0x0024 /* IrDA-SIR10 baudrate count */ -#define IRIF_SIR3 0x0026 /* IrDA-SIR10 status */ -#define IRIF_SIR_FRM 0x0028 /* Hardware frame processing set */ -#define IRIF_SIR_EOF 0x002A /* EOF value */ -#define IRIF_SIR_FLG 0x002C /* Flag clear */ -#define IRIF_UART_STS2 0x002E /* UART status 2 */ -#define IRIF_UART0 0x0030 /* UART control */ -#define IRIF_UART1 0x0032 /* UART status */ -#define IRIF_UART2 0x0034 /* UART mode */ -#define IRIF_UART3 0x0036 /* UART transmit data */ -#define IRIF_UART4 0x0038 /* UART receive data */ -#define IRIF_UART5 0x003A /* UART interrupt mask */ -#define IRIF_UART6 0x003C /* UART baud rate error correction */ -#define IRIF_UART7 0x003E /* UART baud rate count set */ -#define IRIF_CRC0 0x0040 /* CRC engine control */ -#define IRIF_CRC1 0x0042 /* CRC engine input data */ -#define IRIF_CRC2 0x0044 /* CRC engine calculation */ -#define IRIF_CRC3 0x0046 /* CRC engine output data 1 */ -#define IRIF_CRC4 0x0048 /* CRC engine output data 2 */ - -/* IRIF_SIR0 */ -#define IRTPW (1 << 1) /* transmit pulse width select */ -#define IRERRC (1 << 0) /* Clear receive pulse width error */ - -/* IRIF_SIR3 */ -#define IRERR (1 << 0) /* received pulse width Error */ - -/* IRIF_SIR_FRM */ -#define EOFD (1 << 9) /* EOF detection flag */ -#define FRER (1 << 8) /* Frame Error bit */ -#define FRP (1 << 0) /* Frame processing set */ - -/* IRIF_UART_STS2 */ -#define IRSME (1 << 6) /* Receive Sum Error flag */ -#define IROVE (1 << 5) /* Receive Overrun Error flag */ -#define IRFRE (1 << 4) /* Receive Framing Error flag */ -#define IRPRE (1 << 3) /* Receive Parity Error flag */ - -/* IRIF_UART0_*/ -#define TBEC (1 << 2) /* Transmit Data Clear */ -#define RIE (1 << 1) /* Receive Enable */ -#define TIE (1 << 0) /* Transmit Enable */ - -/* IRIF_UART1 */ -#define URSME (1 << 6) /* Receive Sum Error Flag */ -#define UROVE (1 << 5) /* Receive Overrun Error Flag */ -#define URFRE (1 << 4) /* Receive Framing Error Flag */ -#define URPRE (1 << 3) /* Receive Parity Error Flag */ -#define RBF (1 << 2) /* Receive Buffer Full Flag */ -#define TSBE (1 << 1) /* Transmit Shift Buffer Empty Flag */ -#define TBE (1 << 0) /* Transmit Buffer Empty flag */ -#define TBCOMP (TSBE | TBE) - -/* IRIF_UART5 */ -#define RSEIM (1 << 6) /* Receive Sum Error Flag IRQ Mask */ -#define RBFIM (1 << 2) /* Receive Buffer Full Flag IRQ Mask */ -#define TSBEIM (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */ -#define TBEIM (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */ -#define RX_MASK (RSEIM | RBFIM) - -/* IRIF_CRC0 */ -#define CRC_RST (1 << 15) /* CRC Engine Reset */ -#define CRC_CT_MASK 0x0FFF - -/************************************************************************ - - - structure - - -************************************************************************/ -struct sh_sir_self { - void __iomem *membase; - unsigned int irq; - struct clk *clk; - - struct net_device *ndev; - - struct irlap_cb *irlap; - struct qos_info qos; - - iobuff_t tx_buff; - iobuff_t rx_buff; -}; - -/************************************************************************ - - - common function - - -************************************************************************/ -static void sh_sir_write(struct sh_sir_self *self, u32 offset, u16 data) -{ - iowrite16(data, self->membase + offset); -} - -static u16 sh_sir_read(struct sh_sir_self *self, u32 offset) -{ - return ioread16(self->membase + offset); -} - -static void sh_sir_update_bits(struct sh_sir_self *self, u32 offset, - u16 mask, u16 data) -{ - u16 old, new; - - old = sh_sir_read(self, offset); - new = (old & ~mask) | data; - if (old != new) - sh_sir_write(self, offset, new); -} - -/************************************************************************ - - - CRC function - - -************************************************************************/ -static void sh_sir_crc_reset(struct sh_sir_self *self) -{ - sh_sir_write(self, IRIF_CRC0, CRC_RST); -} - -static void sh_sir_crc_add(struct sh_sir_self *self, u8 data) -{ - sh_sir_write(self, IRIF_CRC1, (u16)data); -} - -static u16 sh_sir_crc_cnt(struct sh_sir_self *self) -{ - return CRC_CT_MASK & sh_sir_read(self, IRIF_CRC0); -} - -static u16 sh_sir_crc_out(struct sh_sir_self *self) -{ - return sh_sir_read(self, IRIF_CRC4); -} - -static int sh_sir_crc_init(struct sh_sir_self *self) -{ - struct device *dev = &self->ndev->dev; - int ret = -EIO; - u16 val; - - sh_sir_crc_reset(self); - - sh_sir_crc_add(self, 0xCC); - sh_sir_crc_add(self, 0xF5); - sh_sir_crc_add(self, 0xF1); - sh_sir_crc_add(self, 0xA7); - - val = sh_sir_crc_cnt(self); - if (4 != val) { - dev_err(dev, "CRC count error %x\n", val); - goto crc_init_out; - } - - val = sh_sir_crc_out(self); - if (0x51DF != val) { - dev_err(dev, "CRC result error%x\n", val); - goto crc_init_out; - } - - ret = 0; - -crc_init_out: - - sh_sir_crc_reset(self); - return ret; -} - -/************************************************************************ - - - baud rate functions - - -************************************************************************/ -#define SCLK_BASE 1843200 /* 1.8432MHz */ - -static u32 sh_sir_find_sclk(struct clk *irda_clk) -{ - struct cpufreq_frequency_table *freq_table = irda_clk->freq_table; - struct cpufreq_frequency_table *pos; - struct clk *pclk = clk_get(NULL, "peripheral_clk"); - u32 limit, min = 0xffffffff, tmp; - int index = 0; - - limit = clk_get_rate(pclk); - clk_put(pclk); - - /* IrDA can not set over peripheral_clk */ - cpufreq_for_each_valid_entry_idx(pos, freq_table, index) { - u32 freq = pos->frequency; - - /* IrDA should not over peripheral_clk */ - if (freq > limit) - continue; - - tmp = freq % SCLK_BASE; - if (tmp < min) { - min = tmp; - break; - } - } - - return freq_table[index].frequency; -} - -#define ERR_ROUNDING(a) ((a + 5000) / 10000) -static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate) -{ - struct clk *clk; - struct device *dev = &self->ndev->dev; - u32 rate; - u16 uabca, uabc; - u16 irbca, irbc; - u32 min, rerr, tmp; - int i; - - /* Baud Rate Error Correction x 10000 */ - u32 rate_err_array[] = { - 0, 625, 1250, 1875, - 2500, 3125, 3750, 4375, - 5000, 5625, 6250, 6875, - 7500, 8125, 8750, 9375, - }; - - /* - * FIXME - * - * it support 9600 only now - */ - switch (baudrate) { - case 9600: - break; - default: - dev_err(dev, "un-supported baudrate %d\n", baudrate); - return -EIO; - } - - clk = clk_get(NULL, "irda_clk"); - if (IS_ERR(clk)) { - dev_err(dev, "can not get irda_clk\n"); - return -EIO; - } - - clk_set_rate(clk, sh_sir_find_sclk(clk)); - rate = clk_get_rate(clk); - clk_put(clk); - - dev_dbg(dev, "selected sclk = %d\n", rate); - - /* - * CALCULATION - * - * 1843200 = system rate / (irbca + (irbc + 1)) - */ - - irbc = rate / SCLK_BASE; - - tmp = rate - (SCLK_BASE * irbc); - tmp *= 10000; - - rerr = tmp / SCLK_BASE; - - min = 0xffffffff; - irbca = 0; - for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) { - tmp = abs(rate_err_array[i] - rerr); - if (min > tmp) { - min = tmp; - irbca = i; - } - } - - tmp = rate / (irbc + ERR_ROUNDING(rate_err_array[irbca])); - if ((SCLK_BASE / 100) < abs(tmp - SCLK_BASE)) - dev_warn(dev, "IrDA freq error margin over %d\n", tmp); - - dev_dbg(dev, "target = %d, result = %d, infrared = %d.%d\n", - SCLK_BASE, tmp, irbc, rate_err_array[irbca]); - - irbca = (irbca & 0xF) << 4; - irbc = (irbc - 1) & 0xF; - - if (!irbc) { - dev_err(dev, "sh_sir can not set 0 in IRIF_SIR2\n"); - return -EIO; - } - - sh_sir_write(self, IRIF_SIR0, IRTPW | IRERRC); - sh_sir_write(self, IRIF_SIR1, irbca); - sh_sir_write(self, IRIF_SIR2, irbc); - - /* - * CALCULATION - * - * BaudRate[bps] = system rate / (uabca + (uabc + 1) x 16) - */ - - uabc = rate / baudrate; - uabc = (uabc / 16) - 1; - uabc = (uabc + 1) * 16; - - tmp = rate - (uabc * baudrate); - tmp *= 10000; - - rerr = tmp / baudrate; - - min = 0xffffffff; - uabca = 0; - for (i = 0; i < ARRAY_SIZE(rate_err_array); i++) { - tmp = abs(rate_err_array[i] - rerr); - if (min > tmp) { - min = tmp; - uabca = i; - } - } - - tmp = rate / (uabc + ERR_ROUNDING(rate_err_array[uabca])); - if ((baudrate / 100) < abs(tmp - baudrate)) - dev_warn(dev, "UART freq error margin over %d\n", tmp); - - dev_dbg(dev, "target = %d, result = %d, uart = %d.%d\n", - baudrate, tmp, - uabc, rate_err_array[uabca]); - - uabca = (uabca & 0xF) << 4; - uabc = (uabc / 16) - 1; - - sh_sir_write(self, IRIF_UART6, uabca); - sh_sir_write(self, IRIF_UART7, uabc); - - return 0; -} - -/************************************************************************ - - - iobuf function - - -************************************************************************/ -static int __sh_sir_init_iobuf(iobuff_t *io, int size) -{ - io->head = kmalloc(size, GFP_KERNEL); - if (!io->head) - return -ENOMEM; - - io->truesize = size; - io->in_frame = FALSE; - io->state = OUTSIDE_FRAME; - io->data = io->head; - - return 0; -} - -static void sh_sir_remove_iobuf(struct sh_sir_self *self) -{ - kfree(self->rx_buff.head); - kfree(self->tx_buff.head); - - self->rx_buff.head = NULL; - self->tx_buff.head = NULL; -} - -static int sh_sir_init_iobuf(struct sh_sir_self *self, int rxsize, int txsize) -{ - int err = -ENOMEM; - - if (self->rx_buff.head || - self->tx_buff.head) { - dev_err(&self->ndev->dev, "iobuff has already existed."); - return err; - } - - err = __sh_sir_init_iobuf(&self->rx_buff, rxsize); - if (err) - goto iobuf_err; - - err = __sh_sir_init_iobuf(&self->tx_buff, txsize); - -iobuf_err: - if (err) - sh_sir_remove_iobuf(self); - - return err; -} - -/************************************************************************ - - - status function - - -************************************************************************/ -static void sh_sir_clear_all_err(struct sh_sir_self *self) -{ - /* Clear error flag for receive pulse width */ - sh_sir_update_bits(self, IRIF_SIR0, IRERRC, IRERRC); - - /* Clear frame / EOF error flag */ - sh_sir_write(self, IRIF_SIR_FLG, 0xffff); - - /* Clear all status error */ - sh_sir_write(self, IRIF_UART_STS2, 0); -} - -static void sh_sir_set_phase(struct sh_sir_self *self, int phase) -{ - u16 uart5 = 0; - u16 uart0 = 0; - - switch (phase) { - case TX_PHASE: - uart5 = TBEIM; - uart0 = TBEC | TIE; - break; - case TX_COMP_PHASE: - uart5 = TSBEIM; - uart0 = TIE; - break; - case RX_PHASE: - uart5 = RX_MASK; - uart0 = RIE; - break; - default: - break; - } - - sh_sir_write(self, IRIF_UART5, uart5); - sh_sir_write(self, IRIF_UART0, uart0); -} - -static int sh_sir_is_which_phase(struct sh_sir_self *self) -{ - u16 val = sh_sir_read(self, IRIF_UART5); - - if (val & TBEIM) - return TX_PHASE; - - if (val & TSBEIM) - return TX_COMP_PHASE; - - if (val & RX_MASK) - return RX_PHASE; - - return NONE_PHASE; -} - -static void sh_sir_tx(struct sh_sir_self *self, int phase) -{ - switch (phase) { - case TX_PHASE: - if (0 >= self->tx_buff.len) { - sh_sir_set_phase(self, TX_COMP_PHASE); - } else { - sh_sir_write(self, IRIF_UART3, self->tx_buff.data[0]); - self->tx_buff.len--; - self->tx_buff.data++; - } - break; - case TX_COMP_PHASE: - sh_sir_set_phase(self, RX_PHASE); - netif_wake_queue(self->ndev); - break; - default: - dev_err(&self->ndev->dev, "should not happen\n"); - break; - } -} - -static int sh_sir_read_data(struct sh_sir_self *self) -{ - u16 val = 0; - int timeout = 1024; - - while (timeout--) { - val = sh_sir_read(self, IRIF_UART1); - - /* data get */ - if (val & RBF) { - if (val & (URSME | UROVE | URFRE | URPRE)) - break; - - return (int)sh_sir_read(self, IRIF_UART4); - } - - udelay(1); - } - - dev_err(&self->ndev->dev, "UART1 %04x : STATUS %04x\n", - val, sh_sir_read(self, IRIF_UART_STS2)); - - /* read data register for clear error */ - sh_sir_read(self, IRIF_UART4); - - return -1; -} - -static void sh_sir_rx(struct sh_sir_self *self) -{ - int timeout = 1024; - int data; - - while (timeout--) { - data = sh_sir_read_data(self); - if (data < 0) - break; - - async_unwrap_char(self->ndev, &self->ndev->stats, - &self->rx_buff, (u8)data); - - if (EOFD & sh_sir_read(self, IRIF_SIR_FRM)) - continue; - - break; - } -} - -static irqreturn_t sh_sir_irq(int irq, void *dev_id) -{ - struct sh_sir_self *self = dev_id; - struct device *dev = &self->ndev->dev; - int phase = sh_sir_is_which_phase(self); - - switch (phase) { - case TX_COMP_PHASE: - case TX_PHASE: - sh_sir_tx(self, phase); - break; - case RX_PHASE: - if (sh_sir_read(self, IRIF_SIR3)) - dev_err(dev, "rcv pulse width error occurred\n"); - - sh_sir_rx(self); - sh_sir_clear_all_err(self); - break; - default: - dev_err(dev, "unknown interrupt\n"); - } - - return IRQ_HANDLED; -} - -/************************************************************************ - - - net_device_ops function - - -************************************************************************/ -static int sh_sir_hard_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - struct sh_sir_self *self = netdev_priv(ndev); - int speed = irda_get_next_speed(skb); - - if ((0 < speed) && - (9600 != speed)) { - dev_err(&ndev->dev, "support 9600 only (%d)\n", speed); - return -EIO; - } - - netif_stop_queue(ndev); - - self->tx_buff.data = self->tx_buff.head; - self->tx_buff.len = 0; - if (skb->len) - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - sh_sir_set_phase(self, TX_PHASE); - dev_kfree_skb(skb); - - return 0; -} - -static int sh_sir_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd) -{ - /* - * FIXME - * - * This function is needed for irda framework. - * But nothing to do now - */ - return 0; -} - -static struct net_device_stats *sh_sir_stats(struct net_device *ndev) -{ - struct sh_sir_self *self = netdev_priv(ndev); - - return &self->ndev->stats; -} - -static int sh_sir_open(struct net_device *ndev) -{ - struct sh_sir_self *self = netdev_priv(ndev); - int err; - - clk_enable(self->clk); - err = sh_sir_crc_init(self); - if (err) - goto open_err; - - sh_sir_set_baudrate(self, 9600); - - self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME); - if (!self->irlap) { - err = -ENODEV; - goto open_err; - } - - /* - * Now enable the interrupt then start the queue - */ - sh_sir_update_bits(self, IRIF_SIR_FRM, FRP, FRP); - sh_sir_read(self, IRIF_UART1); /* flag clear */ - sh_sir_read(self, IRIF_UART4); /* flag clear */ - sh_sir_set_phase(self, RX_PHASE); - - netif_start_queue(ndev); - - dev_info(&self->ndev->dev, "opened\n"); - - return 0; - -open_err: - clk_disable(self->clk); - - return err; -} - -static int sh_sir_stop(struct net_device *ndev) -{ - struct sh_sir_self *self = netdev_priv(ndev); - - /* Stop IrLAP */ - if (self->irlap) { - irlap_close(self->irlap); - self->irlap = NULL; - } - - netif_stop_queue(ndev); - - dev_info(&ndev->dev, "stopped\n"); - - return 0; -} - -static const struct net_device_ops sh_sir_ndo = { - .ndo_open = sh_sir_open, - .ndo_stop = sh_sir_stop, - .ndo_start_xmit = sh_sir_hard_xmit, - .ndo_do_ioctl = sh_sir_ioctl, - .ndo_get_stats = sh_sir_stats, -}; - -/************************************************************************ - - - platform_driver function - - -************************************************************************/ -static int sh_sir_probe(struct platform_device *pdev) -{ - struct net_device *ndev; - struct sh_sir_self *self; - struct resource *res; - char clk_name[8]; - int irq; - int err = -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || irq < 0) { - dev_err(&pdev->dev, "Not enough platform resources.\n"); - goto exit; - } - - ndev = alloc_irdadev(sizeof(*self)); - if (!ndev) - goto exit; - - self = netdev_priv(ndev); - self->membase = ioremap_nocache(res->start, resource_size(res)); - if (!self->membase) { - err = -ENXIO; - dev_err(&pdev->dev, "Unable to ioremap.\n"); - goto err_mem_1; - } - - err = sh_sir_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME); - if (err) - goto err_mem_2; - - snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id); - self->clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(self->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); - err = -ENODEV; - goto err_mem_3; - } - - irda_init_max_qos_capabilies(&self->qos); - - ndev->netdev_ops = &sh_sir_ndo; - ndev->irq = irq; - - self->ndev = ndev; - self->qos.baud_rate.bits &= IR_9600; /* FIXME */ - self->qos.min_turn_time.bits = 1; /* 10 ms or more */ - - irda_qos_bits_to_value(&self->qos); - - err = register_netdev(ndev); - if (err) - goto err_mem_4; - - platform_set_drvdata(pdev, ndev); - err = devm_request_irq(&pdev->dev, irq, sh_sir_irq, 0, "sh_sir", self); - if (err) { - dev_warn(&pdev->dev, "Unable to attach sh_sir interrupt\n"); - goto err_mem_4; - } - - dev_info(&pdev->dev, "SuperH IrDA probed\n"); - - goto exit; - -err_mem_4: - clk_put(self->clk); -err_mem_3: - sh_sir_remove_iobuf(self); -err_mem_2: - iounmap(self->membase); -err_mem_1: - free_netdev(ndev); -exit: - return err; -} - -static int sh_sir_remove(struct platform_device *pdev) -{ - struct net_device *ndev = platform_get_drvdata(pdev); - struct sh_sir_self *self = netdev_priv(ndev); - - if (!self) - return 0; - - unregister_netdev(ndev); - clk_put(self->clk); - sh_sir_remove_iobuf(self); - iounmap(self->membase); - free_netdev(ndev); - - return 0; -} - -static struct platform_driver sh_sir_driver = { - .probe = sh_sir_probe, - .remove = sh_sir_remove, - .driver = { - .name = DRIVER_NAME, - }, -}; - -module_platform_driver(sh_sir_driver); - -MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); -MODULE_DESCRIPTION("SuperH IrDA driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/sir-dev.h b/drivers/staging/irda/drivers/sir-dev.h deleted file mode 100644 index f50b9c1c0639..000000000000 --- a/drivers/staging/irda/drivers/sir-dev.h +++ /dev/null @@ -1,191 +0,0 @@ -/********************************************************************* - * - * sir.h: include file for irda-sir device abstraction layer - * - * Copyright (c) 2002 Martin Diehl - * - * 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. - * - ********************************************************************/ - -#ifndef IRDA_SIR_H -#define IRDA_SIR_H - -#include <linux/netdevice.h> -#include <linux/workqueue.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> // iobuff_t - -struct sir_fsm { - struct semaphore sem; - struct delayed_work work; - unsigned state, substate; - int param; - int result; -}; - -#define SIRDEV_STATE_WAIT_TX_COMPLETE 0x0100 - -/* substates for wait_tx_complete */ -#define SIRDEV_STATE_WAIT_XMIT 0x0101 -#define SIRDEV_STATE_WAIT_UNTIL_SENT 0x0102 -#define SIRDEV_STATE_TX_DONE 0x0103 - -#define SIRDEV_STATE_DONGLE_OPEN 0x0300 - -/* 0x0301-0x03ff reserved for individual dongle substates */ - -#define SIRDEV_STATE_DONGLE_CLOSE 0x0400 - -/* 0x0401-0x04ff reserved for individual dongle substates */ - -#define SIRDEV_STATE_SET_DTR_RTS 0x0500 - -#define SIRDEV_STATE_SET_SPEED 0x0700 -#define SIRDEV_STATE_DONGLE_CHECK 0x0800 -#define SIRDEV_STATE_DONGLE_RESET 0x0900 - -/* 0x0901-0x09ff reserved for individual dongle substates */ - -#define SIRDEV_STATE_DONGLE_SPEED 0x0a00 -/* 0x0a01-0x0aff reserved for individual dongle substates */ - -#define SIRDEV_STATE_PORT_SPEED 0x0b00 -#define SIRDEV_STATE_DONE 0x0c00 -#define SIRDEV_STATE_ERROR 0x0d00 -#define SIRDEV_STATE_COMPLETE 0x0e00 - -#define SIRDEV_STATE_DEAD 0xffff - - -struct sir_dev; - -struct dongle_driver { - - struct module *owner; - - const char *driver_name; - - IRDA_DONGLE type; - - int (*open)(struct sir_dev *dev); - int (*close)(struct sir_dev *dev); - int (*reset)(struct sir_dev *dev); - int (*set_speed)(struct sir_dev *dev, unsigned speed); - - struct list_head dongle_list; -}; - -struct sir_driver { - - struct module *owner; - - const char *driver_name; - - int qos_mtt_bits; - - int (*chars_in_buffer)(struct sir_dev *dev); - void (*wait_until_sent)(struct sir_dev *dev); - int (*set_speed)(struct sir_dev *dev, unsigned speed); - int (*set_dtr_rts)(struct sir_dev *dev, int dtr, int rts); - - int (*do_write)(struct sir_dev *dev, const unsigned char *ptr, size_t len); - - int (*start_dev)(struct sir_dev *dev); - int (*stop_dev)(struct sir_dev *dev); -}; - - -/* exported */ - -int irda_register_dongle(struct dongle_driver *new); -int irda_unregister_dongle(struct dongle_driver *drv); - -struct sir_dev *sirdev_get_instance(const struct sir_driver *drv, - const char *name); -int sirdev_put_instance(struct sir_dev *self); - -int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type); -void sirdev_write_complete(struct sir_dev *dev); -int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count); - -/* low level helpers for SIR device/dongle setup */ -int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len); -int sirdev_raw_read(struct sir_dev *dev, char *buf, int len); -int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts); - -/* not exported */ - -int sirdev_get_dongle(struct sir_dev *self, IRDA_DONGLE type); -int sirdev_put_dongle(struct sir_dev *self); - -void sirdev_enable_rx(struct sir_dev *dev); -int sirdev_schedule_request(struct sir_dev *dev, int state, unsigned param); - -/* inline helpers */ - -static inline int sirdev_schedule_speed(struct sir_dev *dev, unsigned speed) -{ - return sirdev_schedule_request(dev, SIRDEV_STATE_SET_SPEED, speed); -} - -static inline int sirdev_schedule_dongle_open(struct sir_dev *dev, int dongle_id) -{ - return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_OPEN, dongle_id); -} - -static inline int sirdev_schedule_dongle_close(struct sir_dev *dev) -{ - return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_CLOSE, 0); -} - -static inline int sirdev_schedule_dtr_rts(struct sir_dev *dev, int dtr, int rts) -{ - int dtrrts; - - dtrrts = ((dtr) ? 0x02 : 0x00) | ((rts) ? 0x01 : 0x00); - return sirdev_schedule_request(dev, SIRDEV_STATE_SET_DTR_RTS, dtrrts); -} - -#if 0 -static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode) -{ - return sirdev_schedule_request(dev, SIRDEV_STATE_SET_MODE, mode); -} -#endif - - -struct sir_dev { - struct net_device *netdev; - - struct irlap_cb *irlap; - - struct qos_info qos; - - char hwname[32]; - - struct sir_fsm fsm; - atomic_t enable_rx; - int raw_tx; - spinlock_t tx_lock; - - u32 new_speed; - u32 flags; - - unsigned speed; - - iobuff_t tx_buff; /* Transmit buffer */ - iobuff_t rx_buff; /* Receive buffer */ - struct sk_buff *tx_skb; - - const struct dongle_driver * dongle_drv; - const struct sir_driver * drv; - void *priv; - -}; - -#endif /* IRDA_SIR_H */ diff --git a/drivers/staging/irda/drivers/sir_dev.c b/drivers/staging/irda/drivers/sir_dev.c deleted file mode 100644 index 6af26a7d787c..000000000000 --- a/drivers/staging/irda/drivers/sir_dev.c +++ /dev/null @@ -1,987 +0,0 @@ -/********************************************************************* - * - * sir_dev.c: irda sir network device - * - * Copyright (c) 2002 Martin Diehl - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - ********************************************************************/ - -#include <linux/hardirq.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/irda_device.h> - -#include "sir-dev.h" - - -static struct workqueue_struct *irda_sir_wq; - -/* STATE MACHINE */ - -/* substate handler of the config-fsm to handle the cases where we want - * to wait for transmit completion before changing the port configuration - */ - -static int sirdev_tx_complete_fsm(struct sir_dev *dev) -{ - struct sir_fsm *fsm = &dev->fsm; - unsigned next_state, delay; - unsigned bytes_left; - - do { - next_state = fsm->substate; /* default: stay in current substate */ - delay = 0; - - switch(fsm->substate) { - - case SIRDEV_STATE_WAIT_XMIT: - if (dev->drv->chars_in_buffer) - bytes_left = dev->drv->chars_in_buffer(dev); - else - bytes_left = 0; - if (!bytes_left) { - next_state = SIRDEV_STATE_WAIT_UNTIL_SENT; - break; - } - - if (dev->speed > 115200) - delay = (bytes_left*8*10000) / (dev->speed/100); - else if (dev->speed > 0) - delay = (bytes_left*10*10000) / (dev->speed/100); - else - delay = 0; - /* expected delay (usec) until remaining bytes are sent */ - if (delay < 100) { - udelay(delay); - delay = 0; - break; - } - /* sleep some longer delay (msec) */ - delay = (delay+999) / 1000; - break; - - case SIRDEV_STATE_WAIT_UNTIL_SENT: - /* block until underlaying hardware buffer are empty */ - if (dev->drv->wait_until_sent) - dev->drv->wait_until_sent(dev); - next_state = SIRDEV_STATE_TX_DONE; - break; - - case SIRDEV_STATE_TX_DONE: - return 0; - - default: - net_err_ratelimited("%s - undefined state\n", __func__); - return -EINVAL; - } - fsm->substate = next_state; - } while (delay == 0); - return delay; -} - -/* - * Function sirdev_config_fsm - * - * State machine to handle the configuration of the device (and attached dongle, if any). - * This handler is scheduled for execution in kIrDAd context, so we can sleep. - * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too - * long. Instead, for longer delays we start a timer to reschedule us later. - * On entry, fsm->sem is always locked and the netdev xmit queue stopped. - * Both must be unlocked/restarted on completion - but only on final exit. - */ - -static void sirdev_config_fsm(struct work_struct *work) -{ - struct sir_dev *dev = container_of(work, struct sir_dev, fsm.work.work); - struct sir_fsm *fsm = &dev->fsm; - int next_state; - int ret = -1; - unsigned delay; - - pr_debug("%s(), <%ld>\n", __func__, jiffies); - - do { - pr_debug("%s - state=0x%04x / substate=0x%04x\n", - __func__, fsm->state, fsm->substate); - - next_state = fsm->state; - delay = 0; - - switch(fsm->state) { - - case SIRDEV_STATE_DONGLE_OPEN: - if (dev->dongle_drv != NULL) { - ret = sirdev_put_dongle(dev); - if (ret) { - fsm->result = -EINVAL; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - - /* Initialize dongle */ - ret = sirdev_get_dongle(dev, fsm->param); - if (ret) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - - /* Dongles are powered through the modem control lines which - * were just set during open. Before resetting, let's wait for - * the power to stabilize. This is what some dongle drivers did - * in open before, while others didn't - should be safe anyway. - */ - - delay = 50; - fsm->substate = SIRDEV_STATE_DONGLE_RESET; - next_state = SIRDEV_STATE_DONGLE_RESET; - - fsm->param = 9600; - - break; - - case SIRDEV_STATE_DONGLE_CLOSE: - /* shouldn't we just treat this as success=? */ - if (dev->dongle_drv == NULL) { - fsm->result = -EINVAL; - next_state = SIRDEV_STATE_ERROR; - break; - } - - ret = sirdev_put_dongle(dev); - if (ret) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_SET_DTR_RTS: - ret = sirdev_set_dtr_rts(dev, - (fsm->param&0x02) ? TRUE : FALSE, - (fsm->param&0x01) ? TRUE : FALSE); - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_SET_SPEED: - fsm->substate = SIRDEV_STATE_WAIT_XMIT; - next_state = SIRDEV_STATE_DONGLE_CHECK; - break; - - case SIRDEV_STATE_DONGLE_CHECK: - ret = sirdev_tx_complete_fsm(dev); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - if ((delay=ret) != 0) - break; - - if (dev->dongle_drv) { - fsm->substate = SIRDEV_STATE_DONGLE_RESET; - next_state = SIRDEV_STATE_DONGLE_RESET; - } - else { - dev->speed = fsm->param; - next_state = SIRDEV_STATE_PORT_SPEED; - } - break; - - case SIRDEV_STATE_DONGLE_RESET: - if (dev->dongle_drv->reset) { - ret = dev->dongle_drv->reset(dev); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - else - ret = 0; - if ((delay=ret) == 0) { - /* set serial port according to dongle default speed */ - if (dev->drv->set_speed) - dev->drv->set_speed(dev, dev->speed); - fsm->substate = SIRDEV_STATE_DONGLE_SPEED; - next_state = SIRDEV_STATE_DONGLE_SPEED; - } - break; - - case SIRDEV_STATE_DONGLE_SPEED: - if (dev->dongle_drv->set_speed) { - ret = dev->dongle_drv->set_speed(dev, fsm->param); - if (ret < 0) { - fsm->result = ret; - next_state = SIRDEV_STATE_ERROR; - break; - } - } - else - ret = 0; - if ((delay=ret) == 0) - next_state = SIRDEV_STATE_PORT_SPEED; - break; - - case SIRDEV_STATE_PORT_SPEED: - /* Finally we are ready to change the serial port speed */ - if (dev->drv->set_speed) - dev->drv->set_speed(dev, dev->speed); - dev->new_speed = 0; - next_state = SIRDEV_STATE_DONE; - break; - - case SIRDEV_STATE_DONE: - /* Signal network layer so it can send more frames */ - netif_wake_queue(dev->netdev); - next_state = SIRDEV_STATE_COMPLETE; - break; - - default: - net_err_ratelimited("%s - undefined state\n", __func__); - fsm->result = -EINVAL; - /* fall thru */ - - case SIRDEV_STATE_ERROR: - net_err_ratelimited("%s - error: %d\n", - __func__, fsm->result); - -#if 0 /* don't enable this before we have netdev->tx_timeout to recover */ - netif_stop_queue(dev->netdev); -#else - netif_wake_queue(dev->netdev); -#endif - /* fall thru */ - - case SIRDEV_STATE_COMPLETE: - /* config change finished, so we are not busy any longer */ - sirdev_enable_rx(dev); - up(&fsm->sem); - return; - } - fsm->state = next_state; - } while(!delay); - - queue_delayed_work(irda_sir_wq, &fsm->work, msecs_to_jiffies(delay)); -} - -/* schedule some device configuration task for execution by kIrDAd - * on behalf of the above state machine. - * can be called from process or interrupt/tasklet context. - */ - -int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param) -{ - struct sir_fsm *fsm = &dev->fsm; - - pr_debug("%s - state=0x%04x / param=%u\n", __func__, - initial_state, param); - - if (down_trylock(&fsm->sem)) { - if (in_interrupt() || in_atomic() || irqs_disabled()) { - pr_debug("%s(), state machine busy!\n", __func__); - return -EWOULDBLOCK; - } else - down(&fsm->sem); - } - - if (fsm->state == SIRDEV_STATE_DEAD) { - /* race with sirdev_close should never happen */ - net_err_ratelimited("%s(), instance staled!\n", __func__); - up(&fsm->sem); - return -ESTALE; /* or better EPIPE? */ - } - - netif_stop_queue(dev->netdev); - atomic_set(&dev->enable_rx, 0); - - fsm->state = initial_state; - fsm->param = param; - fsm->result = 0; - - INIT_DELAYED_WORK(&fsm->work, sirdev_config_fsm); - queue_delayed_work(irda_sir_wq, &fsm->work, 0); - return 0; -} - - -/***************************************************************************/ - -void sirdev_enable_rx(struct sir_dev *dev) -{ - if (unlikely(atomic_read(&dev->enable_rx))) - return; - - /* flush rx-buffer - should also help in case of problems with echo cancelation */ - dev->rx_buff.data = dev->rx_buff.head; - dev->rx_buff.len = 0; - dev->rx_buff.in_frame = FALSE; - dev->rx_buff.state = OUTSIDE_FRAME; - atomic_set(&dev->enable_rx, 1); -} - -static int sirdev_is_receiving(struct sir_dev *dev) -{ - if (!atomic_read(&dev->enable_rx)) - return 0; - - return dev->rx_buff.state != OUTSIDE_FRAME; -} - -int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type) -{ - int err; - - pr_debug("%s : requesting dongle %d.\n", __func__, type); - - err = sirdev_schedule_dongle_open(dev, type); - if (unlikely(err)) - return err; - down(&dev->fsm.sem); /* block until config change completed */ - err = dev->fsm.result; - up(&dev->fsm.sem); - return err; -} -EXPORT_SYMBOL(sirdev_set_dongle); - -/* used by dongle drivers for dongle programming */ - -int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len) -{ - unsigned long flags; - int ret; - - if (unlikely(len > dev->tx_buff.truesize)) - return -ENOSPC; - - spin_lock_irqsave(&dev->tx_lock, flags); /* serialize with other tx operations */ - while (dev->tx_buff.len > 0) { /* wait until tx idle */ - spin_unlock_irqrestore(&dev->tx_lock, flags); - msleep(10); - spin_lock_irqsave(&dev->tx_lock, flags); - } - - dev->tx_buff.data = dev->tx_buff.head; - memcpy(dev->tx_buff.data, buf, len); - dev->tx_buff.len = len; - - ret = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); - if (ret > 0) { - pr_debug("%s(), raw-tx started\n", __func__); - - dev->tx_buff.data += ret; - dev->tx_buff.len -= ret; - dev->raw_tx = 1; - ret = len; /* all data is going to be sent */ - } - spin_unlock_irqrestore(&dev->tx_lock, flags); - return ret; -} -EXPORT_SYMBOL(sirdev_raw_write); - -/* seems some dongle drivers may need this */ - -int sirdev_raw_read(struct sir_dev *dev, char *buf, int len) -{ - int count; - - if (atomic_read(&dev->enable_rx)) - return -EIO; /* fail if we expect irda-frames */ - - count = (len < dev->rx_buff.len) ? len : dev->rx_buff.len; - - if (count > 0) { - memcpy(buf, dev->rx_buff.data, count); - dev->rx_buff.data += count; - dev->rx_buff.len -= count; - } - - /* remaining stuff gets flushed when re-enabling normal rx */ - - return count; -} -EXPORT_SYMBOL(sirdev_raw_read); - -int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) -{ - int ret = -ENXIO; - if (dev->drv->set_dtr_rts) - ret = dev->drv->set_dtr_rts(dev, dtr, rts); - return ret; -} -EXPORT_SYMBOL(sirdev_set_dtr_rts); - -/**********************************************************************/ - -/* called from client driver - likely with bh-context - to indicate - * it made some progress with transmission. Hence we send the next - * chunk, if any, or complete the skb otherwise - */ - -void sirdev_write_complete(struct sir_dev *dev) -{ - unsigned long flags; - struct sk_buff *skb; - int actual = 0; - int err; - - spin_lock_irqsave(&dev->tx_lock, flags); - - pr_debug("%s() - dev->tx_buff.len = %d\n", - __func__, dev->tx_buff.len); - - if (likely(dev->tx_buff.len > 0)) { - /* Write data left in transmit buffer */ - actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); - - if (likely(actual>0)) { - dev->tx_buff.data += actual; - dev->tx_buff.len -= actual; - } - else if (unlikely(actual<0)) { - /* could be dropped later when we have tx_timeout to recover */ - net_err_ratelimited("%s: drv->do_write failed (%d)\n", - __func__, actual); - if ((skb=dev->tx_skb) != NULL) { - dev->tx_skb = NULL; - dev_kfree_skb_any(skb); - dev->netdev->stats.tx_errors++; - dev->netdev->stats.tx_dropped++; - } - dev->tx_buff.len = 0; - } - if (dev->tx_buff.len > 0) - goto done; /* more data to send later */ - } - - if (unlikely(dev->raw_tx != 0)) { - /* in raw mode we are just done now after the buffer was sent - * completely. Since this was requested by some dongle driver - * running under the control of the irda-thread we must take - * care here not to re-enable the queue. The queue will be - * restarted when the irda-thread has completed the request. - */ - - pr_debug("%s(), raw-tx done\n", __func__); - dev->raw_tx = 0; - goto done; /* no post-frame handling in raw mode */ - } - - /* we have finished now sending this skb. - * update statistics and free the skb. - * finally we check and trigger a pending speed change, if any. - * if not we switch to rx mode and wake the queue for further - * packets. - * note the scheduled speed request blocks until the lower - * client driver and the corresponding hardware has really - * finished sending all data (xmit fifo drained f.e.) - * before the speed change gets finally done and the queue - * re-activated. - */ - - pr_debug("%s(), finished with frame!\n", __func__); - - if ((skb=dev->tx_skb) != NULL) { - dev->tx_skb = NULL; - dev->netdev->stats.tx_packets++; - dev->netdev->stats.tx_bytes += skb->len; - dev_kfree_skb_any(skb); - } - - if (unlikely(dev->new_speed > 0)) { - pr_debug("%s(), Changing speed!\n", __func__); - err = sirdev_schedule_speed(dev, dev->new_speed); - if (unlikely(err)) { - /* should never happen - * forget the speed change and hope the stack recovers - */ - net_err_ratelimited("%s - schedule speed change failed: %d\n", - __func__, err); - netif_wake_queue(dev->netdev); - } - /* else: success - * speed change in progress now - * on completion dev->new_speed gets cleared, - * rx-reenabled and the queue restarted - */ - } - else { - sirdev_enable_rx(dev); - netif_wake_queue(dev->netdev); - } - -done: - spin_unlock_irqrestore(&dev->tx_lock, flags); -} -EXPORT_SYMBOL(sirdev_write_complete); - -/* called from client driver - likely with bh-context - to give us - * some more received bytes. We put them into the rx-buffer, - * normally unwrapping and building LAP-skb's (unless rx disabled) - */ - -int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) -{ - if (!dev || !dev->netdev) { - net_warn_ratelimited("%s(), not ready yet!\n", __func__); - return -1; - } - - if (!dev->irlap) { - net_warn_ratelimited("%s - too early: %p / %zd!\n", - __func__, cp, count); - return -1; - } - - if (cp==NULL) { - /* error already at lower level receive - * just update stats and set media busy - */ - irda_device_set_media_busy(dev->netdev, TRUE); - dev->netdev->stats.rx_dropped++; - pr_debug("%s; rx-drop: %zd\n", __func__, count); - return 0; - } - - /* Read the characters into the buffer */ - if (likely(atomic_read(&dev->enable_rx))) { - while (count--) - /* Unwrap and destuff one byte */ - async_unwrap_char(dev->netdev, &dev->netdev->stats, - &dev->rx_buff, *cp++); - } else { - while (count--) { - /* rx not enabled: save the raw bytes and never - * trigger any netif_rx. The received bytes are flushed - * later when we re-enable rx but might be read meanwhile - * by the dongle driver. - */ - dev->rx_buff.data[dev->rx_buff.len++] = *cp++; - - /* What should we do when the buffer is full? */ - if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize)) - dev->rx_buff.len = 0; - } - } - - return 0; -} -EXPORT_SYMBOL(sirdev_receive); - -/**********************************************************************/ - -/* callbacks from network layer */ - -static netdev_tx_t sirdev_hard_xmit(struct sk_buff *skb, - struct net_device *ndev) -{ - struct sir_dev *dev = netdev_priv(ndev); - unsigned long flags; - int actual = 0; - int err; - s32 speed; - - IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); - - netif_stop_queue(ndev); - - pr_debug("%s(), skb->len = %d\n", __func__, skb->len); - - speed = irda_get_next_speed(skb); - if ((speed != dev->speed) && (speed != -1)) { - if (!skb->len) { - err = sirdev_schedule_speed(dev, speed); - if (unlikely(err == -EWOULDBLOCK)) { - /* Failed to initiate the speed change, likely the fsm - * is still busy (pretty unlikely, but...) - * We refuse to accept the skb and return with the queue - * stopped so the network layer will retry after the - * fsm completes and wakes the queue. - */ - return NETDEV_TX_BUSY; - } - else if (unlikely(err)) { - /* other fatal error - forget the speed change and - * hope the stack will recover somehow - */ - netif_start_queue(ndev); - } - /* else: success - * speed change in progress now - * on completion the queue gets restarted - */ - - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } else - dev->new_speed = speed; - } - - /* Init tx buffer*/ - dev->tx_buff.data = dev->tx_buff.head; - - /* Check problems */ - if(spin_is_locked(&dev->tx_lock)) { - pr_debug("%s(), write not completed\n", __func__); - } - - /* serialize with write completion */ - spin_lock_irqsave(&dev->tx_lock, flags); - - /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ - dev->tx_buff.len = async_wrap_skb(skb, dev->tx_buff.data, dev->tx_buff.truesize); - - /* transmission will start now - disable receive. - * if we are just in the middle of an incoming frame, - * treat it as collision. probably it's a good idea to - * reset the rx_buf OUTSIDE_FRAME in this case too? - */ - atomic_set(&dev->enable_rx, 0); - if (unlikely(sirdev_is_receiving(dev))) - dev->netdev->stats.collisions++; - - actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); - - if (likely(actual > 0)) { - dev->tx_skb = skb; - dev->tx_buff.data += actual; - dev->tx_buff.len -= actual; - } - else if (unlikely(actual < 0)) { - /* could be dropped later when we have tx_timeout to recover */ - net_err_ratelimited("%s: drv->do_write failed (%d)\n", - __func__, actual); - dev_kfree_skb_any(skb); - dev->netdev->stats.tx_errors++; - dev->netdev->stats.tx_dropped++; - netif_wake_queue(ndev); - } - spin_unlock_irqrestore(&dev->tx_lock, flags); - - return NETDEV_TX_OK; -} - -/* called from network layer with rtnl hold */ - -static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct sir_dev *dev = netdev_priv(ndev); - int ret = 0; - - IRDA_ASSERT(dev != NULL, return -1;); - - pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, ndev->name, cmd); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else - ret = sirdev_schedule_speed(dev, irq->ifr_baudrate); - /* cannot sleep here for completion - * we are called from network layer with rtnl hold - */ - break; - - case SIOCSDONGLE: /* Set dongle */ - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else - ret = sirdev_schedule_dongle_open(dev, irq->ifr_dongle); - /* cannot sleep here for completion - * we are called from network layer with rtnl hold - */ - break; - - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else - irda_device_set_media_busy(dev->netdev, TRUE); - break; - - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = sirdev_is_receiving(dev); - break; - - case SIOCSDTRRTS: - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else - ret = sirdev_schedule_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); - /* cannot sleep here for completion - * we are called from network layer with rtnl hold - */ - break; - - case SIOCSMODE: -#if 0 - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else - ret = sirdev_schedule_mode(dev, irq->ifr_mode); - /* cannot sleep here for completion - * we are called from network layer with rtnl hold - */ - break; -#endif - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -/* ----------------------------------------------------------------------------- */ - -#define SIRBUF_ALLOCSIZE 4269 /* worst case size of a wrapped IrLAP frame */ - -static int sirdev_alloc_buffers(struct sir_dev *dev) -{ - dev->tx_buff.truesize = SIRBUF_ALLOCSIZE; - dev->rx_buff.truesize = IRDA_SKB_MAX_MTU; - - /* Bootstrap ZeroCopy Rx */ - dev->rx_buff.skb = __netdev_alloc_skb(dev->netdev, dev->rx_buff.truesize, - GFP_KERNEL); - if (dev->rx_buff.skb == NULL) - return -ENOMEM; - skb_reserve(dev->rx_buff.skb, 1); - dev->rx_buff.head = dev->rx_buff.skb->data; - - dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL); - if (dev->tx_buff.head == NULL) { - kfree_skb(dev->rx_buff.skb); - dev->rx_buff.skb = NULL; - dev->rx_buff.head = NULL; - return -ENOMEM; - } - - dev->tx_buff.data = dev->tx_buff.head; - dev->rx_buff.data = dev->rx_buff.head; - dev->tx_buff.len = 0; - dev->rx_buff.len = 0; - - dev->rx_buff.in_frame = FALSE; - dev->rx_buff.state = OUTSIDE_FRAME; - return 0; -}; - -static void sirdev_free_buffers(struct sir_dev *dev) -{ - kfree_skb(dev->rx_buff.skb); - kfree(dev->tx_buff.head); - dev->rx_buff.head = dev->tx_buff.head = NULL; - dev->rx_buff.skb = NULL; -} - -static int sirdev_open(struct net_device *ndev) -{ - struct sir_dev *dev = netdev_priv(ndev); - const struct sir_driver *drv = dev->drv; - - if (!drv) - return -ENODEV; - - /* increase the reference count of the driver module before doing serious stuff */ - if (!try_module_get(drv->owner)) - return -ESTALE; - - if (sirdev_alloc_buffers(dev)) - goto errout_dec; - - if (!dev->drv->start_dev || dev->drv->start_dev(dev)) - goto errout_free; - - sirdev_enable_rx(dev); - dev->raw_tx = 0; - - netif_start_queue(ndev); - dev->irlap = irlap_open(ndev, &dev->qos, dev->hwname); - if (!dev->irlap) - goto errout_stop; - - netif_wake_queue(ndev); - - pr_debug("%s - done, speed = %d\n", __func__, dev->speed); - - return 0; - -errout_stop: - atomic_set(&dev->enable_rx, 0); - if (dev->drv->stop_dev) - dev->drv->stop_dev(dev); -errout_free: - sirdev_free_buffers(dev); -errout_dec: - module_put(drv->owner); - return -EAGAIN; -} - -static int sirdev_close(struct net_device *ndev) -{ - struct sir_dev *dev = netdev_priv(ndev); - const struct sir_driver *drv; - -/* pr_debug("%s\n", __func__); */ - - netif_stop_queue(ndev); - - down(&dev->fsm.sem); /* block on pending config completion */ - - atomic_set(&dev->enable_rx, 0); - - if (unlikely(!dev->irlap)) - goto out; - irlap_close(dev->irlap); - dev->irlap = NULL; - - drv = dev->drv; - if (unlikely(!drv || !dev->priv)) - goto out; - - if (drv->stop_dev) - drv->stop_dev(dev); - - sirdev_free_buffers(dev); - module_put(drv->owner); - -out: - dev->speed = 0; - up(&dev->fsm.sem); - return 0; -} - -static const struct net_device_ops sirdev_ops = { - .ndo_start_xmit = sirdev_hard_xmit, - .ndo_open = sirdev_open, - .ndo_stop = sirdev_close, - .ndo_do_ioctl = sirdev_ioctl, -}; -/* ----------------------------------------------------------------------------- */ - -struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name) -{ - struct net_device *ndev; - struct sir_dev *dev; - - pr_debug("%s - %s\n", __func__, name); - - /* instead of adding tests to protect against drv->do_write==NULL - * at several places we refuse to create a sir_dev instance for - * drivers which don't implement do_write. - */ - if (!drv || !drv->do_write) - return NULL; - - /* - * Allocate new instance of the device - */ - ndev = alloc_irdadev(sizeof(*dev)); - if (ndev == NULL) { - net_err_ratelimited("%s - Can't allocate memory for IrDA control block!\n", - __func__); - goto out; - } - dev = netdev_priv(ndev); - - irda_init_max_qos_capabilies(&dev->qos); - dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - dev->qos.min_turn_time.bits = drv->qos_mtt_bits; - irda_qos_bits_to_value(&dev->qos); - - strncpy(dev->hwname, name, sizeof(dev->hwname)-1); - - atomic_set(&dev->enable_rx, 0); - dev->tx_skb = NULL; - - spin_lock_init(&dev->tx_lock); - sema_init(&dev->fsm.sem, 1); - - dev->drv = drv; - dev->netdev = ndev; - - /* Override the network functions we need to use */ - ndev->netdev_ops = &sirdev_ops; - - if (register_netdev(ndev)) { - net_err_ratelimited("%s(), register_netdev() failed!\n", - __func__); - goto out_freenetdev; - } - - return dev; - -out_freenetdev: - free_netdev(ndev); -out: - return NULL; -} -EXPORT_SYMBOL(sirdev_get_instance); - -int sirdev_put_instance(struct sir_dev *dev) -{ - int err = 0; - - pr_debug("%s\n", __func__); - - atomic_set(&dev->enable_rx, 0); - - netif_carrier_off(dev->netdev); - netif_device_detach(dev->netdev); - - if (dev->dongle_drv) - err = sirdev_schedule_dongle_close(dev); - if (err) - net_err_ratelimited("%s - error %d\n", __func__, err); - - sirdev_close(dev->netdev); - - down(&dev->fsm.sem); - dev->fsm.state = SIRDEV_STATE_DEAD; /* mark staled */ - dev->dongle_drv = NULL; - dev->priv = NULL; - up(&dev->fsm.sem); - - /* Remove netdevice */ - unregister_netdev(dev->netdev); - - free_netdev(dev->netdev); - - return 0; -} -EXPORT_SYMBOL(sirdev_put_instance); - -static int __init sir_wq_init(void) -{ - irda_sir_wq = create_singlethread_workqueue("irda_sir_wq"); - if (!irda_sir_wq) - return -ENOMEM; - return 0; -} - -static void __exit sir_wq_exit(void) -{ - destroy_workqueue(irda_sir_wq); -} - -module_init(sir_wq_init); -module_exit(sir_wq_exit); - -MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>"); -MODULE_DESCRIPTION("IrDA SIR core"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/irda/drivers/sir_dongle.c b/drivers/staging/irda/drivers/sir_dongle.c deleted file mode 100644 index 7436f73ff1bb..000000000000 --- a/drivers/staging/irda/drivers/sir_dongle.c +++ /dev/null @@ -1,133 +0,0 @@ -/********************************************************************* - * - * sir_dongle.c: manager for serial dongle protocol drivers - * - * Copyright (c) 2002 Martin Diehl - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/kmod.h> -#include <linux/mutex.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -/************************************************************************** - * - * dongle registration and attachment - * - */ - -static LIST_HEAD(dongle_list); /* list of registered dongle drivers */ -static DEFINE_MUTEX(dongle_list_lock); /* protects the list */ - -int irda_register_dongle(struct dongle_driver *new) -{ - struct list_head *entry; - struct dongle_driver *drv; - - pr_debug("%s : registering dongle \"%s\" (%d).\n", - __func__, new->driver_name, new->type); - - mutex_lock(&dongle_list_lock); - list_for_each(entry, &dongle_list) { - drv = list_entry(entry, struct dongle_driver, dongle_list); - if (new->type == drv->type) { - mutex_unlock(&dongle_list_lock); - return -EEXIST; - } - } - list_add(&new->dongle_list, &dongle_list); - mutex_unlock(&dongle_list_lock); - return 0; -} -EXPORT_SYMBOL(irda_register_dongle); - -int irda_unregister_dongle(struct dongle_driver *drv) -{ - mutex_lock(&dongle_list_lock); - list_del(&drv->dongle_list); - mutex_unlock(&dongle_list_lock); - return 0; -} -EXPORT_SYMBOL(irda_unregister_dongle); - -int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type) -{ - struct list_head *entry; - const struct dongle_driver *drv = NULL; - int err = -EINVAL; - - request_module("irda-dongle-%d", type); - - if (dev->dongle_drv != NULL) - return -EBUSY; - - /* serialize access to the list of registered dongles */ - mutex_lock(&dongle_list_lock); - - list_for_each(entry, &dongle_list) { - drv = list_entry(entry, struct dongle_driver, dongle_list); - if (drv->type == type) - break; - else - drv = NULL; - } - - if (!drv) { - err = -ENODEV; - goto out_unlock; /* no such dongle */ - } - - /* handling of SMP races with dongle module removal - three cases: - * 1) dongle driver was already unregistered - then we haven't found the - * requested dongle above and are already out here - * 2) the module is already marked deleted but the driver is still - * registered - then the try_module_get() below will fail - * 3) the try_module_get() below succeeds before the module is marked - * deleted - then sys_delete_module() fails and prevents the removal - * because the module is in use. - */ - - if (!try_module_get(drv->owner)) { - err = -ESTALE; - goto out_unlock; /* rmmod already pending */ - } - dev->dongle_drv = drv; - - if (!drv->open || (err=drv->open(dev))!=0) - goto out_reject; /* failed to open driver */ - - mutex_unlock(&dongle_list_lock); - return 0; - -out_reject: - dev->dongle_drv = NULL; - module_put(drv->owner); -out_unlock: - mutex_unlock(&dongle_list_lock); - return err; -} - -int sirdev_put_dongle(struct sir_dev *dev) -{ - const struct dongle_driver *drv = dev->dongle_drv; - - if (drv) { - if (drv->close) - drv->close(dev); /* close this dongle instance */ - - dev->dongle_drv = NULL; /* unlink the dongle driver */ - module_put(drv->owner);/* decrement driver's module refcount */ - } - - return 0; -} diff --git a/drivers/staging/irda/drivers/smsc-ircc2.c b/drivers/staging/irda/drivers/smsc-ircc2.c deleted file mode 100644 index 19a55cba6beb..000000000000 --- a/drivers/staging/irda/drivers/smsc-ircc2.c +++ /dev/null @@ -1,3026 +0,0 @@ -/********************************************************************* - * - * Description: Driver for the SMC Infrared Communications Controller - * Author: Daniele Peri (peri@csai.unipa.it) - * Created at: - * Modified at: - * Modified by: - * - * Copyright (c) 2002 Daniele Peri - * All Rights Reserved. - * Copyright (c) 2002 Jean Tourrilhes - * Copyright (c) 2006 Linus Walleij - * - * - * Based on smc-ircc.c: - * - * Copyright (c) 2001 Stefani Seibold - * Copyright (c) 1999-2001 Dag Brattli - * Copyright (c) 1998-1999 Thomas Davis, - * - * and irport.c: - * - * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved. - * - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/rtnetlink.h> -#include <linux/serial_reg.h> -#include <linux/dma-mapping.h> -#include <linux/pnp.h> -#include <linux/platform_device.h> -#include <linux/gfp.h> - -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/byteorder.h> - -#include <linux/spinlock.h> -#include <linux/pm.h> -#ifdef CONFIG_PCI -#include <linux/pci.h> -#endif - -#include <net/irda/wrapper.h> -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#include "smsc-ircc2.h" -#include "smsc-sio.h" - - -MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>"); -MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver"); -MODULE_LICENSE("GPL"); - -static bool smsc_nopnp = true; -module_param_named(nopnp, smsc_nopnp, bool, 0); -MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true"); - -#define DMA_INVAL 255 -static int ircc_dma = DMA_INVAL; -module_param_hw(ircc_dma, int, dma, 0); -MODULE_PARM_DESC(ircc_dma, "DMA channel"); - -#define IRQ_INVAL 255 -static int ircc_irq = IRQ_INVAL; -module_param_hw(ircc_irq, int, irq, 0); -MODULE_PARM_DESC(ircc_irq, "IRQ line"); - -static int ircc_fir; -module_param_hw(ircc_fir, int, ioport, 0); -MODULE_PARM_DESC(ircc_fir, "FIR Base Address"); - -static int ircc_sir; -module_param_hw(ircc_sir, int, ioport, 0); -MODULE_PARM_DESC(ircc_sir, "SIR Base Address"); - -static int ircc_cfg; -module_param_hw(ircc_cfg, int, ioport, 0); -MODULE_PARM_DESC(ircc_cfg, "Configuration register base address"); - -static int ircc_transceiver; -module_param(ircc_transceiver, int, 0); -MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); - -/* Types */ - -#ifdef CONFIG_PCI -struct smsc_ircc_subsystem_configuration { - unsigned short vendor; /* PCI vendor ID */ - unsigned short device; /* PCI vendor ID */ - unsigned short subvendor; /* PCI subsystem vendor ID */ - unsigned short subdevice; /* PCI subsystem device ID */ - unsigned short sir_io; /* I/O port for SIR */ - unsigned short fir_io; /* I/O port for FIR */ - unsigned char fir_irq; /* FIR IRQ */ - unsigned char fir_dma; /* FIR DMA */ - unsigned short cfg_base; /* I/O port for chip configuration */ - int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ - const char *name; /* name shown as info */ -}; -#endif - -struct smsc_transceiver { - char *name; - void (*set_for_speed)(int fir_base, u32 speed); - int (*probe)(int fir_base); -}; - -struct smsc_chip { - char *name; - #if 0 - u8 type; - #endif - u16 flags; - u8 devid; - u8 rev; -}; - -struct smsc_chip_address { - unsigned int cfg_base; - unsigned int type; -}; - -/* Private data for each instance */ -struct smsc_ircc_cb { - struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct irlap_cb *irlap; /* The link layer we are binded to */ - - chipio_t io; /* IrDA controller information */ - iobuff_t tx_buff; /* Transmit buffer */ - iobuff_t rx_buff; /* Receive buffer */ - dma_addr_t tx_buff_dma; - dma_addr_t rx_buff_dma; - - struct qos_info qos; /* QoS capabilities for this device */ - - spinlock_t lock; /* For serializing operations */ - - __u32 new_speed; - __u32 flags; /* Interface flags */ - - int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */ - int tx_len; /* Number of frames in tx_buff */ - - int transceiver; - struct platform_device *pldev; -}; - -/* Constants */ - -#define SMSC_IRCC2_DRIVER_NAME "smsc-ircc2" - -#define SMSC_IRCC2_C_IRDA_FALLBACK_SPEED 9600 -#define SMSC_IRCC2_C_DEFAULT_TRANSCEIVER 1 -#define SMSC_IRCC2_C_NET_TIMEOUT 0 -#define SMSC_IRCC2_C_SIR_STOP 0 - -static const char *driver_name = SMSC_IRCC2_DRIVER_NAME; - -/* Prototypes */ - -static int smsc_ircc_open(unsigned int firbase, unsigned int sirbase, u8 dma, u8 irq); -static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base); -static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq); -static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self); -static void smsc_ircc_init_chip(struct smsc_ircc_cb *self); -static int __exit smsc_ircc_close(struct smsc_ircc_cb *self); -static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self); -static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self); -static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self); -static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev); -static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev); -static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs); -static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self); -static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed); -static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed); -static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id); -static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev); -static void smsc_ircc_sir_start(struct smsc_ircc_cb *self); -#if SMSC_IRCC2_C_SIR_STOP -static void smsc_ircc_sir_stop(struct smsc_ircc_cb *self); -#endif -static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self); -static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len); -static int smsc_ircc_net_open(struct net_device *dev); -static int smsc_ircc_net_close(struct net_device *dev); -static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#if SMSC_IRCC2_C_NET_TIMEOUT -static void smsc_ircc_timeout(struct net_device *dev); -#endif -static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self); -static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self); -static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed); -static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self); - -/* Probing */ -static int __init smsc_ircc_look_for_chips(void); -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); -static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int __init smsc_superio_fdc(unsigned short cfg_base); -static int __init smsc_superio_lpc(unsigned short cfg_base); -#ifdef CONFIG_PCI -static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); -static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static void __init preconfigure_ali_port(struct pci_dev *dev, - unsigned short port); -static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, - unsigned short ircc_fir, - unsigned short ircc_sir, - unsigned char ircc_dma, - unsigned char ircc_irq); -#endif - -/* Transceivers specific functions */ - -static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed); -static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base); -static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed); -static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base); -static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed); -static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base); - -/* Power Management */ - -static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state); -static int smsc_ircc_resume(struct platform_device *dev); - -static struct platform_driver smsc_ircc_driver = { - .suspend = smsc_ircc_suspend, - .resume = smsc_ircc_resume, - .driver = { - .name = SMSC_IRCC2_DRIVER_NAME, - }, -}; - -/* Transceivers for SMSC-ircc */ - -static struct smsc_transceiver smsc_transceivers[] = -{ - { "Toshiba Satellite 1800 (GP data pin select)", smsc_ircc_set_transceiver_toshiba_sat1800, smsc_ircc_probe_transceiver_toshiba_sat1800 }, - { "Fast pin select", smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select, smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select }, - { "ATC IRMode", smsc_ircc_set_transceiver_smsc_ircc_atc, smsc_ircc_probe_transceiver_smsc_ircc_atc }, - { NULL, NULL } -}; -#define SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS (ARRAY_SIZE(smsc_transceivers) - 1) - -/* SMC SuperIO chipsets definitions */ - -#define KEY55_1 0 /* SuperIO Configuration mode with Key <0x55> */ -#define KEY55_2 1 /* SuperIO Configuration mode with Key <0x55,0x55> */ -#define NoIRDA 2 /* SuperIO Chip has no IRDA Port */ -#define SIR 0 /* SuperIO Chip has only slow IRDA */ -#define FIR 4 /* SuperIO Chip has fast IRDA */ -#define SERx4 8 /* SuperIO Chip supports 115,2 KBaud * 4=460,8 KBaud */ - -static struct smsc_chip __initdata fdc_chips_flat[] = -{ - /* Base address 0x3f0 or 0x370 */ - { "37C44", KEY55_1|NoIRDA, 0x00, 0x00 }, /* This chip cannot be detected */ - { "37C665GT", KEY55_2|NoIRDA, 0x65, 0x01 }, - { "37C665GT", KEY55_2|NoIRDA, 0x66, 0x01 }, - { "37C669", KEY55_2|SIR|SERx4, 0x03, 0x02 }, - { "37C669", KEY55_2|SIR|SERx4, 0x04, 0x02 }, /* ID? */ - { "37C78", KEY55_2|NoIRDA, 0x78, 0x00 }, - { "37N769", KEY55_1|FIR|SERx4, 0x28, 0x00 }, - { "37N869", KEY55_1|FIR|SERx4, 0x29, 0x00 }, - { NULL } -}; - -static struct smsc_chip __initdata fdc_chips_paged[] = -{ - /* Base address 0x3f0 or 0x370 */ - { "37B72X", KEY55_1|SIR|SERx4, 0x4c, 0x00 }, - { "37B77X", KEY55_1|SIR|SERx4, 0x43, 0x00 }, - { "37B78X", KEY55_1|SIR|SERx4, 0x44, 0x00 }, - { "37B80X", KEY55_1|SIR|SERx4, 0x42, 0x00 }, - { "37C67X", KEY55_1|FIR|SERx4, 0x40, 0x00 }, - { "37C93X", KEY55_2|SIR|SERx4, 0x02, 0x01 }, - { "37C93XAPM", KEY55_1|SIR|SERx4, 0x30, 0x01 }, - { "37C93XFR", KEY55_2|FIR|SERx4, 0x03, 0x01 }, - { "37M707", KEY55_1|SIR|SERx4, 0x42, 0x00 }, - { "37M81X", KEY55_1|SIR|SERx4, 0x4d, 0x00 }, - { "37N958FR", KEY55_1|FIR|SERx4, 0x09, 0x04 }, - { "37N971", KEY55_1|FIR|SERx4, 0x0a, 0x00 }, - { "37N972", KEY55_1|FIR|SERx4, 0x0b, 0x00 }, - { NULL } -}; - -static struct smsc_chip __initdata lpc_chips_flat[] = -{ - /* Base address 0x2E or 0x4E */ - { "47N227", KEY55_1|FIR|SERx4, 0x5a, 0x00 }, - { "47N227", KEY55_1|FIR|SERx4, 0x7a, 0x00 }, - { "47N267", KEY55_1|FIR|SERx4, 0x5e, 0x00 }, - { NULL } -}; - -static struct smsc_chip __initdata lpc_chips_paged[] = -{ - /* Base address 0x2E or 0x4E */ - { "47B27X", KEY55_1|SIR|SERx4, 0x51, 0x00 }, - { "47B37X", KEY55_1|SIR|SERx4, 0x52, 0x00 }, - { "47M10X", KEY55_1|SIR|SERx4, 0x59, 0x00 }, - { "47M120", KEY55_1|NoIRDA|SERx4, 0x5c, 0x00 }, - { "47M13X", KEY55_1|SIR|SERx4, 0x59, 0x00 }, - { "47M14X", KEY55_1|SIR|SERx4, 0x5f, 0x00 }, - { "47N252", KEY55_1|FIR|SERx4, 0x0e, 0x00 }, - { "47S42X", KEY55_1|SIR|SERx4, 0x57, 0x00 }, - { NULL } -}; - -#define SMSCSIO_TYPE_FDC 1 -#define SMSCSIO_TYPE_LPC 2 -#define SMSCSIO_TYPE_FLAT 4 -#define SMSCSIO_TYPE_PAGED 8 - -static struct smsc_chip_address __initdata possible_addresses[] = -{ - { 0x3f0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, - { 0x370, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, - { 0xe0, SMSCSIO_TYPE_FDC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, - { 0x2e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, - { 0x4e, SMSCSIO_TYPE_LPC|SMSCSIO_TYPE_FLAT|SMSCSIO_TYPE_PAGED }, - { 0, 0 } -}; - -/* Globals */ - -static struct smsc_ircc_cb *dev_self[] = { NULL, NULL }; -static unsigned short dev_count; - -static inline void register_bank(int iobase, int bank) -{ - outb(((inb(iobase + IRCC_MASTER) & 0xf0) | (bank & 0x07)), - iobase + IRCC_MASTER); -} - -/* PNP hotplug support */ -static const struct pnp_device_id smsc_ircc_pnp_table[] = { - { .id = "SMCf010", .driver_data = 0 }, - /* and presumably others */ - { } -}; -MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table); - -static int pnp_driver_registered; - -#ifdef CONFIG_PNP -static int smsc_ircc_pnp_probe(struct pnp_dev *dev, - const struct pnp_device_id *dev_id) -{ - unsigned int firbase, sirbase; - u8 dma, irq; - - if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && - pnp_dma_valid(dev, 0) && pnp_irq_valid(dev, 0))) - return -EINVAL; - - sirbase = pnp_port_start(dev, 0); - firbase = pnp_port_start(dev, 1); - dma = pnp_dma(dev, 0); - irq = pnp_irq(dev, 0); - - if (smsc_ircc_open(firbase, sirbase, dma, irq)) - return -ENODEV; - - return 0; -} - -static struct pnp_driver smsc_ircc_pnp_driver = { - .name = "smsc-ircc2", - .id_table = smsc_ircc_pnp_table, - .probe = smsc_ircc_pnp_probe, -}; -#else /* CONFIG_PNP */ -static struct pnp_driver smsc_ircc_pnp_driver; -#endif - -/******************************************************************************* - * - * - * SMSC-ircc stuff - * - * - *******************************************************************************/ - -static int __init smsc_ircc_legacy_probe(void) -{ - int ret = 0; - -#ifdef CONFIG_PCI - if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { - /* Ignore errors from preconfiguration */ - net_err_ratelimited("%s, Preconfiguration failed !\n", - driver_name); - } -#endif - - if (ircc_fir > 0 && ircc_sir > 0) { - net_info_ratelimited(" Overriding FIR address 0x%04x\n", - ircc_fir); - net_info_ratelimited(" Overriding SIR address 0x%04x\n", - ircc_sir); - - if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq)) - ret = -ENODEV; - } else { - ret = -ENODEV; - - /* try user provided configuration register base address */ - if (ircc_cfg > 0) { - net_info_ratelimited(" Overriding configuration address 0x%04x\n", - ircc_cfg); - if (!smsc_superio_fdc(ircc_cfg)) - ret = 0; - if (!smsc_superio_lpc(ircc_cfg)) - ret = 0; - } - - if (smsc_ircc_look_for_chips() > 0) - ret = 0; - } - return ret; -} - -/* - * Function smsc_ircc_init () - * - * Initialize chip. Just try to find out how many chips we are dealing with - * and where they are - */ -static int __init smsc_ircc_init(void) -{ - int ret; - - pr_debug("%s\n", __func__); - - ret = platform_driver_register(&smsc_ircc_driver); - if (ret) { - net_err_ratelimited("%s, Can't register driver!\n", - driver_name); - return ret; - } - - dev_count = 0; - - if (smsc_nopnp || !pnp_platform_devices || - ircc_cfg || ircc_fir || ircc_sir || - ircc_dma != DMA_INVAL || ircc_irq != IRQ_INVAL) { - ret = smsc_ircc_legacy_probe(); - } else { - if (pnp_register_driver(&smsc_ircc_pnp_driver) == 0) - pnp_driver_registered = 1; - } - - if (ret) { - if (pnp_driver_registered) - pnp_unregister_driver(&smsc_ircc_pnp_driver); - platform_driver_unregister(&smsc_ircc_driver); - } - - return ret; -} - -static netdev_tx_t smsc_ircc_net_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct smsc_ircc_cb *self = netdev_priv(dev); - - if (self->io.speed > 115200) - return smsc_ircc_hard_xmit_fir(skb, dev); - else - return smsc_ircc_hard_xmit_sir(skb, dev); -} - -static const struct net_device_ops smsc_ircc_netdev_ops = { - .ndo_open = smsc_ircc_net_open, - .ndo_stop = smsc_ircc_net_close, - .ndo_do_ioctl = smsc_ircc_net_ioctl, - .ndo_start_xmit = smsc_ircc_net_xmit, -#if SMSC_IRCC2_C_NET_TIMEOUT - .ndo_tx_timeout = smsc_ircc_timeout, -#endif -}; - -/* - * Function smsc_ircc_open (firbase, sirbase, dma, irq) - * - * Try to open driver instance - * - */ -static int smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) -{ - struct smsc_ircc_cb *self; - struct net_device *dev; - int err; - - pr_debug("%s\n", __func__); - - err = smsc_ircc_present(fir_base, sir_base); - if (err) - goto err_out; - - err = -ENOMEM; - if (dev_count >= ARRAY_SIZE(dev_self)) { - net_warn_ratelimited("%s(), too many devices!\n", __func__); - goto err_out1; - } - - /* - * Allocate new instance of the driver - */ - dev = alloc_irdadev(sizeof(struct smsc_ircc_cb)); - if (!dev) { - net_warn_ratelimited("%s() can't allocate net device\n", - __func__); - goto err_out1; - } - -#if SMSC_IRCC2_C_NET_TIMEOUT - dev->watchdog_timeo = HZ * 2; /* Allow enough time for speed change */ -#endif - dev->netdev_ops = &smsc_ircc_netdev_ops; - - self = netdev_priv(dev); - self->netdev = dev; - - /* Make ifconfig display some details */ - dev->base_addr = self->io.fir_base = fir_base; - dev->irq = self->io.irq = irq; - - /* Need to store self somewhere */ - dev_self[dev_count] = self; - spin_lock_init(&self->lock); - - self->rx_buff.truesize = SMSC_IRCC2_RX_BUFF_TRUESIZE; - self->tx_buff.truesize = SMSC_IRCC2_TX_BUFF_TRUESIZE; - - self->rx_buff.head = - dma_zalloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL); - if (self->rx_buff.head == NULL) - goto err_out2; - - self->tx_buff.head = - dma_zalloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL); - if (self->tx_buff.head == NULL) - goto err_out3; - - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - - smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq); - smsc_ircc_setup_qos(self); - smsc_ircc_init_chip(self); - - if (ircc_transceiver > 0 && - ircc_transceiver < SMSC_IRCC2_C_NUMBER_OF_TRANSCEIVERS) - self->transceiver = ircc_transceiver; - else - smsc_ircc_probe_transceiver(self); - - err = register_netdev(self->netdev); - if (err) { - net_err_ratelimited("%s, Network device registration failed!\n", - driver_name); - goto err_out4; - } - - self->pldev = platform_device_register_simple(SMSC_IRCC2_DRIVER_NAME, - dev_count, NULL, 0); - if (IS_ERR(self->pldev)) { - err = PTR_ERR(self->pldev); - goto err_out5; - } - platform_set_drvdata(self->pldev, self); - - net_info_ratelimited("IrDA: Registered device %s\n", dev->name); - dev_count++; - - return 0; - - err_out5: - unregister_netdev(self->netdev); - - err_out4: - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - err_out3: - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - err_out2: - free_netdev(self->netdev); - dev_self[dev_count] = NULL; - err_out1: - release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT); - release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); - err_out: - return err; -} - -/* - * Function smsc_ircc_present(fir_base, sir_base) - * - * Check the smsc-ircc chip presence - * - */ -static int smsc_ircc_present(unsigned int fir_base, unsigned int sir_base) -{ - unsigned char low, high, chip, config, dma, irq, version; - - if (!request_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT, - driver_name)) { - net_warn_ratelimited("%s: can't get fir_base of 0x%03x\n", - __func__, fir_base); - goto out1; - } - - if (!request_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT, - driver_name)) { - net_warn_ratelimited("%s: can't get sir_base of 0x%03x\n", - __func__, sir_base); - goto out2; - } - - register_bank(fir_base, 3); - - high = inb(fir_base + IRCC_ID_HIGH); - low = inb(fir_base + IRCC_ID_LOW); - chip = inb(fir_base + IRCC_CHIP_ID); - version = inb(fir_base + IRCC_VERSION); - config = inb(fir_base + IRCC_INTERFACE); - dma = config & IRCC_INTERFACE_DMA_MASK; - irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; - - if (high != 0x10 || low != 0xb8 || (chip != 0xf1 && chip != 0xf2)) { - net_warn_ratelimited("%s(), addr 0x%04x - no device found!\n", - __func__, fir_base); - goto out3; - } - net_info_ratelimited("SMsC IrDA Controller found\n IrCC version %d.%d, firport 0x%03x, sirport 0x%03x dma=%d, irq=%d\n", - chip & 0x0f, version, - fir_base, sir_base, dma, irq); - - return 0; - - out3: - release_region(sir_base, SMSC_IRCC2_SIR_CHIP_IO_EXTENT); - out2: - release_region(fir_base, SMSC_IRCC2_FIR_CHIP_IO_EXTENT); - out1: - return -ENODEV; -} - -/* - * Function smsc_ircc_setup_io(self, fir_base, sir_base, dma, irq) - * - * Setup I/O - * - */ -static void smsc_ircc_setup_io(struct smsc_ircc_cb *self, - unsigned int fir_base, unsigned int sir_base, - u8 dma, u8 irq) -{ - unsigned char config, chip_dma, chip_irq; - - register_bank(fir_base, 3); - config = inb(fir_base + IRCC_INTERFACE); - chip_dma = config & IRCC_INTERFACE_DMA_MASK; - chip_irq = (config & IRCC_INTERFACE_IRQ_MASK) >> 4; - - self->io.fir_base = fir_base; - self->io.sir_base = sir_base; - self->io.fir_ext = SMSC_IRCC2_FIR_CHIP_IO_EXTENT; - self->io.sir_ext = SMSC_IRCC2_SIR_CHIP_IO_EXTENT; - self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE; - self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED; - - if (irq != IRQ_INVAL) { - if (irq != chip_irq) - net_info_ratelimited("%s, Overriding IRQ - chip says %d, using %d\n", - driver_name, chip_irq, irq); - self->io.irq = irq; - } else - self->io.irq = chip_irq; - - if (dma != DMA_INVAL) { - if (dma != chip_dma) - net_info_ratelimited("%s, Overriding DMA - chip says %d, using %d\n", - driver_name, chip_dma, dma); - self->io.dma = dma; - } else - self->io.dma = chip_dma; - -} - -/* - * Function smsc_ircc_setup_qos(self) - * - * Setup qos - * - */ -static void smsc_ircc_setup_qos(struct smsc_ircc_cb *self) -{ - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8); - - self->qos.min_turn_time.bits = SMSC_IRCC2_MIN_TURN_TIME; - self->qos.window_size.bits = SMSC_IRCC2_WINDOW_SIZE; - irda_qos_bits_to_value(&self->qos); -} - -/* - * Function smsc_ircc_init_chip(self) - * - * Init chip - * - */ -static void smsc_ircc_init_chip(struct smsc_ircc_cb *self) -{ - int iobase = self->io.fir_base; - - register_bank(iobase, 0); - outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); - outb(0x00, iobase + IRCC_MASTER); - - register_bank(iobase, 1); - outb(((inb(iobase + IRCC_SCE_CFGA) & 0x87) | IRCC_CFGA_IRDA_SIR_A), - iobase + IRCC_SCE_CFGA); - -#ifdef smsc_669 /* Uses pin 88/89 for Rx/Tx */ - outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), - iobase + IRCC_SCE_CFGB); -#else - outb(((inb(iobase + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), - iobase + IRCC_SCE_CFGB); -#endif - (void) inb(iobase + IRCC_FIFO_THRESHOLD); - outb(SMSC_IRCC2_FIFO_THRESHOLD, iobase + IRCC_FIFO_THRESHOLD); - - register_bank(iobase, 4); - outb((inb(iobase + IRCC_CONTROL) & 0x30), iobase + IRCC_CONTROL); - - register_bank(iobase, 0); - outb(0, iobase + IRCC_LCR_A); - - smsc_ircc_set_sir_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); - - /* Power on device */ - outb(0x00, iobase + IRCC_MASTER); -} - -/* - * Function smsc_ircc_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct smsc_ircc_cb *self; - unsigned long flags; - int ret = 0; - - IRDA_ASSERT(dev != NULL, return -1;); - - self = netdev_priv(dev); - - IRDA_ASSERT(self != NULL, return -1;); - - pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else { - /* Make sure we are the only one touching - * self->io.speed and the hardware - Jean II */ - spin_lock_irqsave(&self->lock, flags); - smsc_ircc_change_speed(self, irq->ifr_baudrate); - spin_unlock_irqrestore(&self->lock, flags); - } - break; - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = smsc_ircc_is_receiving(self); - break; - #if 0 - case SIOCSDTRRTS: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - smsc_ircc_sir_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); - break; - #endif - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -#if SMSC_IRCC2_C_NET_TIMEOUT -/* - * Function smsc_ircc_timeout (struct net_device *dev) - * - * The networking timeout management. - * - */ - -static void smsc_ircc_timeout(struct net_device *dev) -{ - struct smsc_ircc_cb *self = netdev_priv(dev); - unsigned long flags; - - net_warn_ratelimited("%s: transmit timed out, changing speed to: %d\n", - dev->name, self->io.speed); - spin_lock_irqsave(&self->lock, flags); - smsc_ircc_sir_start(self); - smsc_ircc_change_speed(self, self->io.speed); - netif_trans_update(dev); /* prevent tx timeout */ - netif_wake_queue(dev); - spin_unlock_irqrestore(&self->lock, flags); -} -#endif - -/* - * Function smsc_ircc_hard_xmit_sir (struct sk_buff *skb, struct net_device *dev) - * - * Transmits the current frame until FIFO is full, then - * waits until the next transmit interrupt, and continues until the - * frame is transmitted. - */ -static netdev_tx_t smsc_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev) -{ - struct smsc_ircc_cb *self; - unsigned long flags; - s32 speed; - - pr_debug("%s\n", __func__); - - IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); - - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); - - netif_stop_queue(dev); - - /* Make sure test of self->io.speed & speed change are atomic */ - spin_lock_irqsave(&self->lock, flags); - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if (speed != self->io.speed && speed != -1) { - /* Check for empty frame */ - if (!skb->len) { - /* - * We send frames one by one in SIR mode (no - * pipelining), so at this point, if we were sending - * a previous frame, we just received the interrupt - * telling us it is finished (UART_IIR_THRI). - * Therefore, waiting for the transmitter to really - * finish draining the fifo won't take too long. - * And the interrupt handler is not expected to run. - * - Jean II */ - smsc_ircc_sir_wait_hw_transmitter_finish(self); - smsc_ircc_change_speed(self, speed); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - self->new_speed = speed; - } - - /* Init tx buffer */ - self->tx_buff.data = self->tx_buff.head; - - /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - dev->stats.tx_bytes += self->tx_buff.len; - - /* Turn on transmit finished interrupt. Will fire immediately! */ - outb(UART_IER_THRI, self->io.sir_base + UART_IER); - - spin_unlock_irqrestore(&self->lock, flags); - - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -/* - * Function smsc_ircc_set_fir_speed (self, baud) - * - * Change the speed of the device - * - */ -static void smsc_ircc_set_fir_speed(struct smsc_ircc_cb *self, u32 speed) -{ - int fir_base, ir_mode, ctrl, fast; - - IRDA_ASSERT(self != NULL, return;); - fir_base = self->io.fir_base; - - self->io.speed = speed; - - switch (speed) { - default: - case 576000: - ir_mode = IRCC_CFGA_IRDA_HDLC; - ctrl = IRCC_CRC; - fast = 0; - pr_debug("%s(), handling baud of 576000\n", __func__); - break; - case 1152000: - ir_mode = IRCC_CFGA_IRDA_HDLC; - ctrl = IRCC_1152 | IRCC_CRC; - fast = IRCC_LCR_A_FAST | IRCC_LCR_A_GP_DATA; - pr_debug("%s(), handling baud of 1152000\n", - __func__); - break; - case 4000000: - ir_mode = IRCC_CFGA_IRDA_4PPM; - ctrl = IRCC_CRC; - fast = IRCC_LCR_A_FAST; - pr_debug("%s(), handling baud of 4000000\n", - __func__); - break; - } - #if 0 - Now in tranceiver! - /* This causes an interrupt */ - register_bank(fir_base, 0); - outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast, fir_base + IRCC_LCR_A); - #endif - - register_bank(fir_base, 1); - outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | ir_mode), fir_base + IRCC_SCE_CFGA); - - register_bank(fir_base, 4); - outb((inb(fir_base + IRCC_CONTROL) & 0x30) | ctrl, fir_base + IRCC_CONTROL); -} - -/* - * Function smsc_ircc_fir_start(self) - * - * Change the speed of the device - * - */ -static void smsc_ircc_fir_start(struct smsc_ircc_cb *self) -{ - struct net_device *dev; - int fir_base; - - pr_debug("%s\n", __func__); - - IRDA_ASSERT(self != NULL, return;); - dev = self->netdev; - IRDA_ASSERT(dev != NULL, return;); - - fir_base = self->io.fir_base; - - /* Reset everything */ - - /* Clear FIFO */ - outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A); - - /* Enable interrupt */ - /*outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, fir_base + IRCC_IER);*/ - - register_bank(fir_base, 1); - - /* Select the TX/RX interface */ -#ifdef SMSC_669 /* Uses pin 88/89 for Rx/Tx */ - outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), - fir_base + IRCC_SCE_CFGB); -#else - outb(((inb(fir_base + IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR), - fir_base + IRCC_SCE_CFGB); -#endif - (void) inb(fir_base + IRCC_FIFO_THRESHOLD); - - /* Enable SCE interrupts */ - outb(0, fir_base + IRCC_MASTER); - register_bank(fir_base, 0); - outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, fir_base + IRCC_IER); - outb(IRCC_MASTER_INT_EN, fir_base + IRCC_MASTER); -} - -/* - * Function smsc_ircc_fir_stop(self, baud) - * - * Change the speed of the device - * - */ -static void smsc_ircc_fir_stop(struct smsc_ircc_cb *self) -{ - int fir_base; - - pr_debug("%s\n", __func__); - - IRDA_ASSERT(self != NULL, return;); - - fir_base = self->io.fir_base; - register_bank(fir_base, 0); - /*outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER);*/ - outb(inb(fir_base + IRCC_LCR_B) & IRCC_LCR_B_SIP_ENABLE, fir_base + IRCC_LCR_B); -} - - -/* - * Function smsc_ircc_change_speed(self, baud) - * - * Change the speed of the device - * - * This function *must* be called with spinlock held, because it may - * be called from the irq handler. - Jean II - */ -static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed) -{ - struct net_device *dev; - int last_speed_was_sir; - - pr_debug("%s() changing speed to: %d\n", __func__, speed); - - IRDA_ASSERT(self != NULL, return;); - dev = self->netdev; - - last_speed_was_sir = self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED; - - #if 0 - /* Temp Hack */ - speed= 1152000; - self->io.speed = speed; - last_speed_was_sir = 0; - smsc_ircc_fir_start(self); - #endif - - if (self->io.speed == 0) - smsc_ircc_sir_start(self); - - #if 0 - if (!last_speed_was_sir) speed = self->io.speed; - #endif - - if (self->io.speed != speed) - smsc_ircc_set_transceiver_for_speed(self, speed); - - self->io.speed = speed; - - if (speed <= SMSC_IRCC2_MAX_SIR_SPEED) { - if (!last_speed_was_sir) { - smsc_ircc_fir_stop(self); - smsc_ircc_sir_start(self); - } - smsc_ircc_set_sir_speed(self, speed); - } else { - if (last_speed_was_sir) { - #if SMSC_IRCC2_C_SIR_STOP - smsc_ircc_sir_stop(self); - #endif - smsc_ircc_fir_start(self); - } - smsc_ircc_set_fir_speed(self, speed); - - #if 0 - self->tx_buff.len = 10; - self->tx_buff.data = self->tx_buff.head; - - smsc_ircc_dma_xmit(self, 4000); - #endif - /* Be ready for incoming frames */ - smsc_ircc_dma_receive(self); - } - - netif_wake_queue(dev); -} - -/* - * Function smsc_ircc_set_sir_speed (self, speed) - * - * Set speed of IrDA port to specified baudrate - * - */ -static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) -{ - int iobase; - int fcr; /* FIFO control reg */ - int lcr; /* Line control reg */ - int divisor; - - pr_debug("%s(), Setting speed to: %d\n", __func__, speed); - - IRDA_ASSERT(self != NULL, return;); - iobase = self->io.sir_base; - - /* Update accounting for new speed */ - self->io.speed = speed; - - /* Turn off interrupts */ - outb(0, iobase + UART_IER); - - divisor = SMSC_IRCC2_MAX_SIR_SPEED / speed; - - fcr = UART_FCR_ENABLE_FIFO; - - /* - * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and - * almost 1,7 ms at 19200 bps. At speeds above that we can just forget - * about this timeout since it will always be fast enough. - */ - fcr |= self->io.speed < 38400 ? - UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14; - - /* IrDA ports use 8N1 */ - lcr = UART_LCR_WLEN8; - - outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ - outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ - outb(divisor >> 8, iobase + UART_DLM); - outb(lcr, iobase + UART_LCR); /* Set 8N1 */ - outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ - - /* Turn on interrups */ - outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); - - pr_debug("%s() speed changed to: %d\n", __func__, speed); -} - - -/* - * Function smsc_ircc_hard_xmit_fir (skb, dev) - * - * Transmit the frame! - * - */ -static netdev_tx_t smsc_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev) -{ - struct smsc_ircc_cb *self; - unsigned long flags; - s32 speed; - int mtt; - - IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;); - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); - - netif_stop_queue(dev); - - /* Make sure test of self->io.speed & speed change are atomic */ - spin_lock_irqsave(&self->lock, flags); - - /* Check if we need to change the speed after this frame */ - speed = irda_get_next_speed(skb); - if (speed != self->io.speed && speed != -1) { - /* Check for empty frame */ - if (!skb->len) { - /* Note : you should make sure that speed changes - * are not going to corrupt any outgoing frame. - * Look at nsc-ircc for the gory details - Jean II */ - smsc_ircc_change_speed(self, speed); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - self->new_speed = speed; - } - - skb_copy_from_linear_data(skb, self->tx_buff.head, skb->len); - - self->tx_buff.len = skb->len; - self->tx_buff.data = self->tx_buff.head; - - mtt = irda_get_mtt(skb); - if (mtt) { - int bofs; - - /* - * Compute how many BOFs (STA or PA's) we need to waste the - * min turn time given the speed of the link. - */ - bofs = mtt * (self->io.speed / 1000) / 8000; - if (bofs > 4095) - bofs = 4095; - - smsc_ircc_dma_xmit(self, bofs); - } else { - /* Transmit frame */ - smsc_ircc_dma_xmit(self, 0); - } - - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -/* - * Function smsc_ircc_dma_xmit (self, bofs) - * - * Transmit data using DMA - * - */ -static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs) -{ - int iobase = self->io.fir_base; - u8 ctrl; - - pr_debug("%s\n", __func__); -#if 1 - /* Disable Rx */ - register_bank(iobase, 0); - outb(0x00, iobase + IRCC_LCR_B); -#endif - register_bank(iobase, 1); - outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, - iobase + IRCC_SCE_CFGB); - - self->io.direction = IO_XMIT; - - /* Set BOF additional count for generating the min turn time */ - register_bank(iobase, 4); - outb(bofs & 0xff, iobase + IRCC_BOF_COUNT_LO); - ctrl = inb(iobase + IRCC_CONTROL) & 0xf0; - outb(ctrl | ((bofs >> 8) & 0x0f), iobase + IRCC_BOF_COUNT_HI); - - /* Set max Tx frame size */ - outb(self->tx_buff.len >> 8, iobase + IRCC_TX_SIZE_HI); - outb(self->tx_buff.len & 0xff, iobase + IRCC_TX_SIZE_LO); - - /*outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);*/ - - /* Enable burst mode chip Tx DMA */ - register_bank(iobase, 1); - outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | - IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB); - - /* Setup DMA controller (must be done after enabling chip DMA) */ - irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, - DMA_TX_MODE); - - /* Enable interrupt */ - - register_bank(iobase, 0); - outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER); - outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER); - - /* Enable transmit */ - outb(IRCC_LCR_B_SCE_TRANSMIT | IRCC_LCR_B_SIP_ENABLE, iobase + IRCC_LCR_B); -} - -/* - * Function smsc_ircc_dma_xmit_complete (self) - * - * The transfer of a frame in finished. This function will only be called - * by the interrupt handler - * - */ -static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self) -{ - int iobase = self->io.fir_base; - - pr_debug("%s\n", __func__); -#if 0 - /* Disable Tx */ - register_bank(iobase, 0); - outb(0x00, iobase + IRCC_LCR_B); -#endif - register_bank(iobase, 1); - outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, - iobase + IRCC_SCE_CFGB); - - /* Check for underrun! */ - register_bank(iobase, 0); - if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) { - self->netdev->stats.tx_errors++; - self->netdev->stats.tx_fifo_errors++; - - /* Reset error condition */ - register_bank(iobase, 0); - outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER); - outb(0x00, iobase + IRCC_MASTER); - } else { - self->netdev->stats.tx_packets++; - self->netdev->stats.tx_bytes += self->tx_buff.len; - } - - /* Check if it's time to change the speed */ - if (self->new_speed) { - smsc_ircc_change_speed(self, self->new_speed); - self->new_speed = 0; - } - - netif_wake_queue(self->netdev); -} - -/* - * Function smsc_ircc_dma_receive(self) - * - * Get ready for receiving a frame. The device will initiate a DMA - * if it starts to receive a frame. - * - */ -static int smsc_ircc_dma_receive(struct smsc_ircc_cb *self) -{ - int iobase = self->io.fir_base; -#if 0 - /* Turn off chip DMA */ - register_bank(iobase, 1); - outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, - iobase + IRCC_SCE_CFGB); -#endif - - /* Disable Tx */ - register_bank(iobase, 0); - outb(0x00, iobase + IRCC_LCR_B); - - /* Turn off chip DMA */ - register_bank(iobase, 1); - outb(inb(iobase + IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, - iobase + IRCC_SCE_CFGB); - - self->io.direction = IO_RECV; - self->rx_buff.data = self->rx_buff.head; - - /* Set max Rx frame size */ - register_bank(iobase, 4); - outb((2050 >> 8) & 0x0f, iobase + IRCC_RX_SIZE_HI); - outb(2050 & 0xff, iobase + IRCC_RX_SIZE_LO); - - /* Setup DMA controller */ - irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, - DMA_RX_MODE); - - /* Enable burst mode chip Rx DMA */ - register_bank(iobase, 1); - outb(inb(iobase + IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | - IRCC_CFGB_DMA_BURST, iobase + IRCC_SCE_CFGB); - - /* Enable interrupt */ - register_bank(iobase, 0); - outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER); - outb(IRCC_MASTER_INT_EN, iobase + IRCC_MASTER); - - /* Enable receiver */ - register_bank(iobase, 0); - outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, - iobase + IRCC_LCR_B); - - return 0; -} - -/* - * Function smsc_ircc_dma_receive_complete(self) - * - * Finished with receiving frames - * - */ -static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) -{ - struct sk_buff *skb; - int len, msgcnt, lsr; - int iobase = self->io.fir_base; - - register_bank(iobase, 0); - - pr_debug("%s\n", __func__); -#if 0 - /* Disable Rx */ - register_bank(iobase, 0); - outb(0x00, iobase + IRCC_LCR_B); -#endif - register_bank(iobase, 0); - outb(inb(iobase + IRCC_LSAR) & ~IRCC_LSAR_ADDRESS_MASK, iobase + IRCC_LSAR); - lsr= inb(iobase + IRCC_LSR); - msgcnt = inb(iobase + IRCC_LCR_B) & 0x08; - - pr_debug("%s: dma count = %d\n", __func__, - get_dma_residue(self->io.dma)); - - len = self->rx_buff.truesize - get_dma_residue(self->io.dma); - - /* Look for errors */ - if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) { - self->netdev->stats.rx_errors++; - if (lsr & IRCC_LSR_FRAME_ERROR) - self->netdev->stats.rx_frame_errors++; - if (lsr & IRCC_LSR_CRC_ERROR) - self->netdev->stats.rx_crc_errors++; - if (lsr & IRCC_LSR_SIZE_ERROR) - self->netdev->stats.rx_length_errors++; - if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) - self->netdev->stats.rx_length_errors++; - return; - } - - /* Remove CRC */ - len -= self->io.speed < 4000000 ? 2 : 4; - - if (len < 2 || len > 2050) { - net_warn_ratelimited("%s(), bogus len=%d\n", __func__, len); - return; - } - pr_debug("%s: msgcnt = %d, len=%d\n", __func__, msgcnt, len); - - skb = dev_alloc_skb(len + 1); - if (!skb) - return; - - /* Make sure IP header gets aligned */ - skb_reserve(skb, 1); - - skb_put_data(skb, self->rx_buff.data, len); - self->netdev->stats.rx_packets++; - self->netdev->stats.rx_bytes += len; - - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); -} - -/* - * Function smsc_ircc_sir_receive (self) - * - * Receive one frame from the infrared port - * - */ -static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) -{ - int boguscount = 0; - int iobase; - - IRDA_ASSERT(self != NULL, return;); - - iobase = self->io.sir_base; - - /* - * Receive all characters in Rx FIFO, unwrap and unstuff them. - * async_unwrap_char will deliver all found frames - */ - do { - async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, - inb(iobase + UART_RX)); - - /* Make sure we don't stay here to long */ - if (boguscount++ > 32) { - pr_debug("%s(), breaking!\n", __func__); - break; - } - } while (inb(iobase + UART_LSR) & UART_LSR_DR); -} - - -/* - * Function smsc_ircc_interrupt (irq, dev_id, regs) - * - * An interrupt from the chip has arrived. Time to do some work - * - */ -static irqreturn_t smsc_ircc_interrupt(int dummy, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smsc_ircc_cb *self = netdev_priv(dev); - int iobase, iir, lcra, lsr; - irqreturn_t ret = IRQ_NONE; - - /* Serialise the interrupt handler in various CPUs, stop Tx path */ - spin_lock(&self->lock); - - /* Check if we should use the SIR interrupt handler */ - if (self->io.speed <= SMSC_IRCC2_MAX_SIR_SPEED) { - ret = smsc_ircc_interrupt_sir(dev); - goto irq_ret_unlock; - } - - iobase = self->io.fir_base; - - register_bank(iobase, 0); - iir = inb(iobase + IRCC_IIR); - if (iir == 0) - goto irq_ret_unlock; - ret = IRQ_HANDLED; - - /* Disable interrupts */ - outb(0, iobase + IRCC_IER); - lcra = inb(iobase + IRCC_LCR_A); - lsr = inb(iobase + IRCC_LSR); - - pr_debug("%s(), iir = 0x%02x\n", __func__, iir); - - if (iir & IRCC_IIR_EOM) { - if (self->io.direction == IO_RECV) - smsc_ircc_dma_receive_complete(self); - else - smsc_ircc_dma_xmit_complete(self); - - smsc_ircc_dma_receive(self); - } - - if (iir & IRCC_IIR_ACTIVE_FRAME) { - /*printk(KERN_WARNING "%s(): Active Frame\n", __func__);*/ - } - - /* Enable interrupts again */ - - register_bank(iobase, 0); - outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase + IRCC_IER); - - irq_ret_unlock: - spin_unlock(&self->lock); - - return ret; -} - -/* - * Function irport_interrupt_sir (irq, dev_id) - * - * Interrupt handler for SIR modes - */ -static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev) -{ - struct smsc_ircc_cb *self = netdev_priv(dev); - int boguscount = 0; - int iobase; - int iir, lsr; - - /* Already locked coming here in smsc_ircc_interrupt() */ - /*spin_lock(&self->lock);*/ - - iobase = self->io.sir_base; - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - if (iir == 0) - return IRQ_NONE; - while (iir) { - /* Clear interrupt */ - lsr = inb(iobase + UART_LSR); - - pr_debug("%s(), iir=%02x, lsr=%02x, iobase=%#x\n", - __func__, iir, lsr, iobase); - - switch (iir) { - case UART_IIR_RLSI: - pr_debug("%s(), RLSI\n", __func__); - break; - case UART_IIR_RDI: - /* Receive interrupt */ - smsc_ircc_sir_receive(self); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) - /* Transmitter ready for data */ - smsc_ircc_sir_write_wakeup(self); - break; - default: - pr_debug("%s(), unhandled IIR=%#x\n", - __func__, iir); - break; - } - - /* Make sure we don't stay here to long */ - if (boguscount++ > 100) - break; - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - } - /*spin_unlock(&self->lock);*/ - return IRQ_HANDLED; -} - - -#if 0 /* unused */ -/* - * Function ircc_is_receiving (self) - * - * Return TRUE is we are currently receiving a frame - * - */ -static int ircc_is_receiving(struct smsc_ircc_cb *self) -{ - int status = FALSE; - /* int iobase; */ - - pr_debug("%s\n", __func__); - - IRDA_ASSERT(self != NULL, return FALSE;); - - pr_debug("%s: dma count = %d\n", __func__, - get_dma_residue(self->io.dma)); - - status = (self->rx_buff.state != OUTSIDE_FRAME); - - return status; -} -#endif /* unused */ - -static int smsc_ircc_request_irq(struct smsc_ircc_cb *self) -{ - int error; - - error = request_irq(self->io.irq, smsc_ircc_interrupt, 0, - self->netdev->name, self->netdev); - if (error) - pr_debug("%s(), unable to allocate irq=%d, err=%d\n", - __func__, self->io.irq, error); - - return error; -} - -static void smsc_ircc_start_interrupts(struct smsc_ircc_cb *self) -{ - unsigned long flags; - - spin_lock_irqsave(&self->lock, flags); - - self->io.speed = 0; - smsc_ircc_change_speed(self, SMSC_IRCC2_C_IRDA_FALLBACK_SPEED); - - spin_unlock_irqrestore(&self->lock, flags); -} - -static void smsc_ircc_stop_interrupts(struct smsc_ircc_cb *self) -{ - int iobase = self->io.fir_base; - unsigned long flags; - - spin_lock_irqsave(&self->lock, flags); - - register_bank(iobase, 0); - outb(0, iobase + IRCC_IER); - outb(IRCC_MASTER_RESET, iobase + IRCC_MASTER); - outb(0x00, iobase + IRCC_MASTER); - - spin_unlock_irqrestore(&self->lock, flags); -} - - -/* - * Function smsc_ircc_net_open (dev) - * - * Start the device - * - */ -static int smsc_ircc_net_open(struct net_device *dev) -{ - struct smsc_ircc_cb *self; - char hwname[16]; - - pr_debug("%s\n", __func__); - - IRDA_ASSERT(dev != NULL, return -1;); - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); - - if (self->io.suspended) { - pr_debug("%s(), device is suspended\n", __func__); - return -EAGAIN; - } - - if (request_irq(self->io.irq, smsc_ircc_interrupt, 0, dev->name, - (void *) dev)) { - pr_debug("%s(), unable to allocate irq=%d\n", - __func__, self->io.irq); - return -EAGAIN; - } - - smsc_ircc_start_interrupts(self); - - /* Give self a hardware name */ - /* It would be cool to offer the chip revision here - Jean II */ - sprintf(hwname, "SMSC @ 0x%03x", self->io.fir_base); - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos, hwname); - - /* - * Always allocate the DMA channel after the IRQ, - * and clean up on failure. - */ - if (request_dma(self->io.dma, dev->name)) { - smsc_ircc_net_close(dev); - - net_warn_ratelimited("%s(), unable to allocate DMA=%d\n", - __func__, self->io.dma); - return -EAGAIN; - } - - netif_start_queue(dev); - - return 0; -} - -/* - * Function smsc_ircc_net_close (dev) - * - * Stop the device - * - */ -static int smsc_ircc_net_close(struct net_device *dev) -{ - struct smsc_ircc_cb *self; - - pr_debug("%s\n", __func__); - - IRDA_ASSERT(dev != NULL, return -1;); - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); - - /* Stop device */ - netif_stop_queue(dev); - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - smsc_ircc_stop_interrupts(self); - - /* if we are called from smsc_ircc_resume we don't have IRQ reserved */ - if (!self->io.suspended) - free_irq(self->io.irq, dev); - - disable_dma(self->io.dma); - free_dma(self->io.dma); - - return 0; -} - -static int smsc_ircc_suspend(struct platform_device *dev, pm_message_t state) -{ - struct smsc_ircc_cb *self = platform_get_drvdata(dev); - - if (!self->io.suspended) { - pr_debug("%s, Suspending\n", driver_name); - - rtnl_lock(); - if (netif_running(self->netdev)) { - netif_device_detach(self->netdev); - smsc_ircc_stop_interrupts(self); - free_irq(self->io.irq, self->netdev); - disable_dma(self->io.dma); - } - self->io.suspended = 1; - rtnl_unlock(); - } - - return 0; -} - -static int smsc_ircc_resume(struct platform_device *dev) -{ - struct smsc_ircc_cb *self = platform_get_drvdata(dev); - - if (self->io.suspended) { - pr_debug("%s, Waking up\n", driver_name); - - rtnl_lock(); - smsc_ircc_init_chip(self); - if (netif_running(self->netdev)) { - if (smsc_ircc_request_irq(self)) { - /* - * Don't fail resume process, just kill this - * network interface - */ - unregister_netdevice(self->netdev); - } else { - enable_dma(self->io.dma); - smsc_ircc_start_interrupts(self); - netif_device_attach(self->netdev); - } - } - self->io.suspended = 0; - rtnl_unlock(); - } - return 0; -} - -/* - * Function smsc_ircc_close (self) - * - * Close driver instance - * - */ -static int __exit smsc_ircc_close(struct smsc_ircc_cb *self) -{ - pr_debug("%s\n", __func__); - - IRDA_ASSERT(self != NULL, return -1;); - - platform_device_unregister(self->pldev); - - /* Remove netdevice */ - unregister_netdev(self->netdev); - - smsc_ircc_stop_interrupts(self); - - /* Release the PORTS that this driver is using */ - pr_debug("%s(), releasing 0x%03x\n", __func__, - self->io.fir_base); - - release_region(self->io.fir_base, self->io.fir_ext); - - pr_debug("%s(), releasing 0x%03x\n", __func__, - self->io.sir_base); - - release_region(self->io.sir_base, self->io.sir_ext); - - if (self->tx_buff.head) - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - - if (self->rx_buff.head) - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - - free_netdev(self->netdev); - - return 0; -} - -static void __exit smsc_ircc_cleanup(void) -{ - int i; - - pr_debug("%s\n", __func__); - - for (i = 0; i < 2; i++) { - if (dev_self[i]) - smsc_ircc_close(dev_self[i]); - } - - if (pnp_driver_registered) - pnp_unregister_driver(&smsc_ircc_pnp_driver); - - platform_driver_unregister(&smsc_ircc_driver); -} - -/* - * Start SIR operations - * - * This function *must* be called with spinlock held, because it may - * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II - */ -static void smsc_ircc_sir_start(struct smsc_ircc_cb *self) -{ - struct net_device *dev; - int fir_base, sir_base; - - pr_debug("%s\n", __func__); - - IRDA_ASSERT(self != NULL, return;); - dev = self->netdev; - IRDA_ASSERT(dev != NULL, return;); - - fir_base = self->io.fir_base; - sir_base = self->io.sir_base; - - /* Reset everything */ - outb(IRCC_MASTER_RESET, fir_base + IRCC_MASTER); - - #if SMSC_IRCC2_C_SIR_STOP - /*smsc_ircc_sir_stop(self);*/ - #endif - - register_bank(fir_base, 1); - outb(((inb(fir_base + IRCC_SCE_CFGA) & IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK) | IRCC_CFGA_IRDA_SIR_A), fir_base + IRCC_SCE_CFGA); - - /* Initialize UART */ - outb(UART_LCR_WLEN8, sir_base + UART_LCR); /* Reset DLAB */ - outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), sir_base + UART_MCR); - - /* Turn on interrups */ - outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, sir_base + UART_IER); - - pr_debug("%s() - exit\n", __func__); - - outb(0x00, fir_base + IRCC_MASTER); -} - -#if SMSC_IRCC2_C_SIR_STOP -void smsc_ircc_sir_stop(struct smsc_ircc_cb *self) -{ - int iobase; - - pr_debug("%s\n", __func__); - iobase = self->io.sir_base; - - /* Reset UART */ - outb(0, iobase + UART_MCR); - - /* Turn off interrupts */ - outb(0, iobase + UART_IER); -} -#endif - -/* - * Function smsc_sir_write_wakeup (self) - * - * Called by the SIR interrupt handler when there's room for more data. - * If we have more packets to send, we send them here. - * - */ -static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self) -{ - int actual = 0; - int iobase; - int fcr; - - IRDA_ASSERT(self != NULL, return;); - - pr_debug("%s\n", __func__); - - iobase = self->io.sir_base; - - /* Finished with frame? */ - if (self->tx_buff.len > 0) { - /* Write data left in transmit buffer */ - actual = smsc_ircc_sir_write(iobase, self->io.fifo_size, - self->tx_buff.data, self->tx_buff.len); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - } else { - - /*if (self->tx_buff.len ==0) {*/ - - /* - * Now serial buffer is almost free & we can start - * transmission of another packet. But first we must check - * if we need to change the speed of the hardware - */ - if (self->new_speed) { - pr_debug("%s(), Changing speed to %d.\n", - __func__, self->new_speed); - smsc_ircc_sir_wait_hw_transmitter_finish(self); - smsc_ircc_change_speed(self, self->new_speed); - self->new_speed = 0; - } else { - /* Tell network layer that we want more frames */ - netif_wake_queue(self->netdev); - } - self->netdev->stats.tx_packets++; - - if (self->io.speed <= 115200) { - /* - * Reset Rx FIFO to make sure that all reflected transmit data - * is discarded. This is needed for half duplex operation - */ - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR; - fcr |= self->io.speed < 38400 ? - UART_FCR_TRIGGER_1 : UART_FCR_TRIGGER_14; - - outb(fcr, iobase + UART_FCR); - - /* Turn on receive interrupts */ - outb(UART_IER_RDI, iobase + UART_IER); - } - } -} - -/* - * Function smsc_ircc_sir_write (iobase, fifo_size, buf, len) - * - * Fill Tx FIFO with transmit data - * - */ -static int smsc_ircc_sir_write(int iobase, int fifo_size, __u8 *buf, int len) -{ - int actual = 0; - - /* Tx FIFO should be empty! */ - if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) { - net_warn_ratelimited("%s(), failed, fifo not empty!\n", - __func__); - return 0; - } - - /* Fill FIFO with current frame */ - while (fifo_size-- > 0 && actual < len) { - /* Transmit next byte */ - outb(buf[actual], iobase + UART_TX); - actual++; - } - return actual; -} - -/* - * Function smsc_ircc_is_receiving (self) - * - * Returns true is we are currently receiving data - * - */ -static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self) -{ - return self->rx_buff.state != OUTSIDE_FRAME; -} - - -/* - * Function smsc_ircc_probe_transceiver(self) - * - * Tries to find the used Transceiver - * - */ -static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self) -{ - unsigned int i; - - IRDA_ASSERT(self != NULL, return;); - - for (i = 0; smsc_transceivers[i].name != NULL; i++) - if (smsc_transceivers[i].probe(self->io.fir_base)) { - net_info_ratelimited(" %s transceiver found\n", - smsc_transceivers[i].name); - self->transceiver= i + 1; - return; - } - - net_info_ratelimited("No transceiver found. Defaulting to %s\n", - smsc_transceivers[SMSC_IRCC2_C_DEFAULT_TRANSCEIVER].name); - - self->transceiver = SMSC_IRCC2_C_DEFAULT_TRANSCEIVER; -} - - -/* - * Function smsc_ircc_set_transceiver_for_speed(self, speed) - * - * Set the transceiver according to the speed - * - */ -static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed) -{ - unsigned int trx; - - trx = self->transceiver; - if (trx > 0) - smsc_transceivers[trx - 1].set_for_speed(self->io.fir_base, speed); -} - -/* - * Function smsc_ircc_wait_hw_transmitter_finish () - * - * Wait for the real end of HW transmission - * - * The UART is a strict FIFO, and we get called only when we have finished - * pushing data to the FIFO, so the maximum amount of time we must wait - * is only for the FIFO to drain out. - * - * We use a simple calibrated loop. We may need to adjust the loop - * delay (udelay) to balance I/O traffic and latency. And we also need to - * adjust the maximum timeout. - * It would probably be better to wait for the proper interrupt, - * but it doesn't seem to be available. - * - * We can't use jiffies or kernel timers because : - * 1) We are called from the interrupt handler, which disable softirqs, - * so jiffies won't be increased - * 2) Jiffies granularity is usually very coarse (10ms), and we don't - * want to wait that long to detect stuck hardware. - * Jean II - */ - -static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self) -{ - int iobase = self->io.sir_base; - int count = SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US; - - /* Calibrated busy loop */ - while (count-- > 0 && !(inb(iobase + UART_LSR) & UART_LSR_TEMT)) - udelay(1); - - if (count < 0) - pr_debug("%s(): stuck transmitter\n", __func__); -} - - -/* PROBING - * - * REVISIT we can be told about the device by PNP, and should use that info - * instead of probing hardware and creating a platform_device ... - */ - -static int __init smsc_ircc_look_for_chips(void) -{ - struct smsc_chip_address *address; - char *type; - unsigned int cfg_base, found; - - found = 0; - address = possible_addresses; - - while (address->cfg_base) { - cfg_base = address->cfg_base; - - /*printk(KERN_WARNING "%s(): probing: 0x%02x for: 0x%02x\n", __func__, cfg_base, address->type);*/ - - if (address->type & SMSCSIO_TYPE_FDC) { - type = "FDC"; - if (address->type & SMSCSIO_TYPE_FLAT) - if (!smsc_superio_flat(fdc_chips_flat, cfg_base, type)) - found++; - - if (address->type & SMSCSIO_TYPE_PAGED) - if (!smsc_superio_paged(fdc_chips_paged, cfg_base, type)) - found++; - } - if (address->type & SMSCSIO_TYPE_LPC) { - type = "LPC"; - if (address->type & SMSCSIO_TYPE_FLAT) - if (!smsc_superio_flat(lpc_chips_flat, cfg_base, type)) - found++; - - if (address->type & SMSCSIO_TYPE_PAGED) - if (!smsc_superio_paged(lpc_chips_paged, cfg_base, type)) - found++; - } - address++; - } - return found; -} - -/* - * Function smsc_superio_flat (chip, base, type) - * - * Try to get configuration of a smc SuperIO chip with flat register model - * - */ -static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfgbase, char *type) -{ - unsigned short firbase, sirbase; - u8 mode, dma, irq; - int ret = -ENODEV; - - pr_debug("%s\n", __func__); - - if (smsc_ircc_probe(cfgbase, SMSCSIOFLAT_DEVICEID_REG, chips, type) == NULL) - return ret; - - outb(SMSCSIOFLAT_UARTMODE0C_REG, cfgbase); - mode = inb(cfgbase + 1); - - /*printk(KERN_WARNING "%s(): mode: 0x%02x\n", __func__, mode);*/ - - if (!(mode & SMSCSIOFLAT_UART2MODE_VAL_IRDA)) - net_warn_ratelimited("%s(): IrDA not enabled\n", __func__); - - outb(SMSCSIOFLAT_UART2BASEADDR_REG, cfgbase); - sirbase = inb(cfgbase + 1) << 2; - - /* FIR iobase */ - outb(SMSCSIOFLAT_FIRBASEADDR_REG, cfgbase); - firbase = inb(cfgbase + 1) << 3; - - /* DMA */ - outb(SMSCSIOFLAT_FIRDMASELECT_REG, cfgbase); - dma = inb(cfgbase + 1) & SMSCSIOFLAT_FIRDMASELECT_MASK; - - /* IRQ */ - outb(SMSCSIOFLAT_UARTIRQSELECT_REG, cfgbase); - irq = inb(cfgbase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; - - net_info_ratelimited("%s(): fir: 0x%02x, sir: 0x%02x, dma: %02d, irq: %d, mode: 0x%02x\n", - __func__, firbase, sirbase, dma, irq, mode); - - if (firbase && smsc_ircc_open(firbase, sirbase, dma, irq) == 0) - ret = 0; - - /* Exit configuration */ - outb(SMSCSIO_CFGEXITKEY, cfgbase); - - return ret; -} - -/* - * Function smsc_superio_paged (chip, base, type) - * - * Try to get configuration of a smc SuperIO chip with paged register model - * - */ -static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type) -{ - unsigned short fir_io, sir_io; - int ret = -ENODEV; - - pr_debug("%s\n", __func__); - - if (smsc_ircc_probe(cfg_base, 0x20, chips, type) == NULL) - return ret; - - /* Select logical device (UART2) */ - outb(0x07, cfg_base); - outb(0x05, cfg_base + 1); - - /* SIR iobase */ - outb(0x60, cfg_base); - sir_io = inb(cfg_base + 1) << 8; - outb(0x61, cfg_base); - sir_io |= inb(cfg_base + 1); - - /* Read FIR base */ - outb(0x62, cfg_base); - fir_io = inb(cfg_base + 1) << 8; - outb(0x63, cfg_base); - fir_io |= inb(cfg_base + 1); - outb(0x2b, cfg_base); /* ??? */ - - if (fir_io && smsc_ircc_open(fir_io, sir_io, ircc_dma, ircc_irq) == 0) - ret = 0; - - /* Exit configuration */ - outb(SMSCSIO_CFGEXITKEY, cfg_base); - - return ret; -} - - -static int __init smsc_access(unsigned short cfg_base, unsigned char reg) -{ - pr_debug("%s\n", __func__); - - outb(reg, cfg_base); - return inb(cfg_base) != reg ? -1 : 0; -} - -static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) -{ - u8 devid, xdevid, rev; - - pr_debug("%s\n", __func__); - - /* Leave configuration */ - - outb(SMSCSIO_CFGEXITKEY, cfg_base); - - if (inb(cfg_base) == SMSCSIO_CFGEXITKEY) /* not a smc superio chip */ - return NULL; - - outb(reg, cfg_base); - - xdevid = inb(cfg_base + 1); - - /* Enter configuration */ - - outb(SMSCSIO_CFGACCESSKEY, cfg_base); - - #if 0 - if (smsc_access(cfg_base,0x55)) /* send second key and check */ - return NULL; - #endif - - /* probe device ID */ - - if (smsc_access(cfg_base, reg)) - return NULL; - - devid = inb(cfg_base + 1); - - if (devid == 0 || devid == 0xff) /* typical values for unused port */ - return NULL; - - /* probe revision ID */ - - if (smsc_access(cfg_base, reg + 1)) - return NULL; - - rev = inb(cfg_base + 1); - - if (rev >= 128) /* i think this will make no sense */ - return NULL; - - if (devid == xdevid) /* protection against false positives */ - return NULL; - - /* Check for expected device ID; are there others? */ - - while (chip->devid != devid) { - - chip++; - - if (chip->name == NULL) - return NULL; - } - - net_info_ratelimited("found SMC SuperIO Chip (devid=0x%02x rev=%02X base=0x%04x): %s%s\n", - devid, rev, cfg_base, type, chip->name); - - if (chip->rev > rev) { - net_info_ratelimited("Revision higher than expected\n"); - return NULL; - } - - if (chip->flags & NoIRDA) - net_info_ratelimited("chipset does not support IRDA\n"); - - return chip; -} - -static int __init smsc_superio_fdc(unsigned short cfg_base) -{ - int ret = -1; - - if (!request_region(cfg_base, 2, driver_name)) { - net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n", - __func__, cfg_base); - } else { - if (!smsc_superio_flat(fdc_chips_flat, cfg_base, "FDC") || - !smsc_superio_paged(fdc_chips_paged, cfg_base, "FDC")) - ret = 0; - - release_region(cfg_base, 2); - } - - return ret; -} - -static int __init smsc_superio_lpc(unsigned short cfg_base) -{ - int ret = -1; - - if (!request_region(cfg_base, 2, driver_name)) { - net_warn_ratelimited("%s: can't get cfg_base of 0x%03x\n", - __func__, cfg_base); - } else { - if (!smsc_superio_flat(lpc_chips_flat, cfg_base, "LPC") || - !smsc_superio_paged(lpc_chips_paged, cfg_base, "LPC")) - ret = 0; - - release_region(cfg_base, 2); - } - return ret; -} - -/* - * Look for some specific subsystem setups that need - * pre-configuration not properly done by the BIOS (especially laptops) - * This code is based in part on smcinit.c, tosh1800-smcinit.c - * and tosh2450-smcinit.c. The table lists the device entries - * for ISA bridges with an LPC (Low Pin Count) controller which - * handles the communication with the SMSC device. After the LPC - * controller is initialized through PCI, the SMSC device is initialized - * through a dedicated port in the ISA port-mapped I/O area, this latter - * area is used to configure the SMSC device with default - * SIR and FIR I/O ports, DMA and IRQ. Different vendors have - * used different sets of parameters and different control port - * addresses making a subsystem device table necessary. - */ -#ifdef CONFIG_PCI -static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { - /* - * Subsystems needing entries: - * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family - * 0x10b9:0x1533 0x0e11:0x005a Compaq nc4000 family - * 0x8086:0x24cc 0x0e11:0x002a HP nx9000 family - */ - { - /* Guessed entry */ - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ - .device = 0x24cc, - .subvendor = 0x103c, - .subdevice = 0x08bc, - .sir_io = 0x02f8, - .fir_io = 0x0130, - .fir_irq = 0x05, - .fir_dma = 0x03, - .cfg_base = 0x004e, - .preconfigure = preconfigure_through_82801, - .name = "HP nx5000 family", - }, - { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ - .device = 0x24cc, - .subvendor = 0x103c, - .subdevice = 0x088c, - /* Quite certain these are the same for nc8000 as for nc6000 */ - .sir_io = 0x02f8, - .fir_io = 0x0130, - .fir_irq = 0x05, - .fir_dma = 0x03, - .cfg_base = 0x004e, - .preconfigure = preconfigure_through_82801, - .name = "HP nc8000 family", - }, - { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ - .device = 0x24cc, - .subvendor = 0x103c, - .subdevice = 0x0890, - .sir_io = 0x02f8, - .fir_io = 0x0130, - .fir_irq = 0x05, - .fir_dma = 0x03, - .cfg_base = 0x004e, - .preconfigure = preconfigure_through_82801, - .name = "HP nc6000 family", - }, - { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ - .device = 0x24cc, - .subvendor = 0x0e11, - .subdevice = 0x0860, - /* I assume these are the same for x1000 as for the others */ - .sir_io = 0x02e8, - .fir_io = 0x02f8, - .fir_irq = 0x07, - .fir_dma = 0x03, - .cfg_base = 0x002e, - .preconfigure = preconfigure_through_82801, - .name = "Compaq x1000 family", - }, - { - /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x24c0, - .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any" */ - .sir_io = 0x03f8, - .fir_io = 0x0130, - .fir_irq = 0x07, - .fir_dma = 0x01, - .cfg_base = 0x002e, - .preconfigure = preconfigure_through_82801, - .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", - }, - { - .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801CAM ISA bridge */ - .device = 0x248c, - .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any" */ - .sir_io = 0x03f8, - .fir_io = 0x0130, - .fir_irq = 0x03, - .fir_dma = 0x03, - .cfg_base = 0x002e, - .preconfigure = preconfigure_through_82801, - .name = "Toshiba laptop with Intel 82801CAM ISA bridge", - }, - { - /* 82801DBM (ICH4-M) LPC Interface Bridge */ - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x24cc, - .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any" */ - .sir_io = 0x03f8, - .fir_io = 0x0130, - .fir_irq = 0x03, - .fir_dma = 0x03, - .cfg_base = 0x002e, - .preconfigure = preconfigure_through_82801, - .name = "Toshiba laptop with Intel 8281DBM LPC bridge", - }, - { - /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ - .vendor = PCI_VENDOR_ID_AL, - .device = 0x1533, - .subvendor = 0x1179, - .subdevice = 0xffff, /* 0xffff is "any" */ - .sir_io = 0x02e8, - .fir_io = 0x02f8, - .fir_irq = 0x07, - .fir_dma = 0x03, - .cfg_base = 0x002e, - .preconfigure = preconfigure_through_ali, - .name = "Toshiba laptop with ALi ISA bridge", - }, - { } // Terminator -}; - - -/* - * This sets up the basic SMSC parameters - * (FIR port, SIR port, FIR DMA, FIR IRQ) - * through the chip configuration port. - */ -static int __init preconfigure_smsc_chip(struct - smsc_ircc_subsystem_configuration - *conf) -{ - unsigned short iobase = conf->cfg_base; - unsigned char tmpbyte; - - outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state - outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID - tmpbyte = inb(iobase +1); // Read device ID - pr_debug("Detected Chip id: 0x%02x, setting up registers...\n", - tmpbyte); - - /* Disable UART1 and set up SIR I/O port */ - outb(0x24, iobase); // select CR24 - UART1 base addr - outb(0x00, iobase + 1); // disable UART1 - outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr - outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 - tmpbyte = inb(iobase + 1); - if (tmpbyte != (conf->sir_io >> 2) ) { - net_warn_ratelimited("ERROR: could not configure SIR ioport\n"); - net_warn_ratelimited("Try to supply ircc_cfg argument\n"); - return -ENXIO; - } - - /* Set up FIR IRQ channel for UART2 */ - outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select - tmpbyte = inb(iobase + 1); - tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion - tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); - outb(tmpbyte, iobase + 1); - tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; - if (tmpbyte != conf->fir_irq) { - net_warn_ratelimited("ERROR: could not configure FIR IRQ channel\n"); - return -ENXIO; - } - - /* Set up FIR I/O port */ - outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr - outb((conf->fir_io >> 3), iobase + 1); - tmpbyte = inb(iobase + 1); - if (tmpbyte != (conf->fir_io >> 3) ) { - net_warn_ratelimited("ERROR: could not configure FIR I/O port\n"); - return -ENXIO; - } - - /* Set up FIR DMA channel */ - outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select - outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA - tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; - if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { - net_warn_ratelimited("ERROR: could not configure FIR DMA channel\n"); - return -ENXIO; - } - - outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode - tmpbyte = inb(iobase + 1); - tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | - SMSCSIOFLAT_UART2MODE_VAL_IRDA; - outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed - - outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel - tmpbyte = inb(iobase + 1); - outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down - - /* This one was not part of tosh1800 */ - outb(0x0a, iobase); // CR0a - ecp fifo / ir mux - tmpbyte = inb(iobase + 1); - outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port - - outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power - tmpbyte = inb(iobase + 1); - outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down - - outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle - tmpbyte = inb(iobase + 1); - outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done - - outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration - - return 0; -} - -/* 82801CAM generic registers */ -#define VID 0x00 -#define DID 0x02 -#define PIRQ_A_D_ROUT 0x60 -#define SIRQ_CNTL 0x64 -#define PIRQ_E_H_ROUT 0x68 -#define PCI_DMA_C 0x90 -/* LPC-specific registers */ -#define COM_DEC 0xe0 -#define GEN1_DEC 0xe4 -#define LPC_EN 0xe6 -#define GEN2_DEC 0xec -/* - * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge - * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. - * They all work the same way! - */ -static int __init preconfigure_through_82801(struct pci_dev *dev, - struct - smsc_ircc_subsystem_configuration - *conf) -{ - unsigned short tmpword; - unsigned char tmpbyte; - - net_info_ratelimited("Setting up Intel 82801 controller and SMSC device\n"); - /* - * Select the range for the COMA COM port (SIR) - * Register COM_DEC: - * Bit 7: reserved - * Bit 6-4, COMB decode range - * Bit 3: reserved - * Bit 2-0, COMA decode range - * - * Decode ranges: - * 000 = 0x3f8-0x3ff (COM1) - * 001 = 0x2f8-0x2ff (COM2) - * 010 = 0x220-0x227 - * 011 = 0x228-0x22f - * 100 = 0x238-0x23f - * 101 = 0x2e8-0x2ef (COM4) - * 110 = 0x338-0x33f - * 111 = 0x3e8-0x3ef (COM3) - */ - pci_read_config_byte(dev, COM_DEC, &tmpbyte); - tmpbyte &= 0xf8; /* mask COMA bits */ - switch(conf->sir_io) { - case 0x3f8: - tmpbyte |= 0x00; - break; - case 0x2f8: - tmpbyte |= 0x01; - break; - case 0x220: - tmpbyte |= 0x02; - break; - case 0x228: - tmpbyte |= 0x03; - break; - case 0x238: - tmpbyte |= 0x04; - break; - case 0x2e8: - tmpbyte |= 0x05; - break; - case 0x338: - tmpbyte |= 0x06; - break; - case 0x3e8: - tmpbyte |= 0x07; - break; - default: - tmpbyte |= 0x01; /* COM2 default */ - } - pr_debug("COM_DEC (write): 0x%02x\n", tmpbyte); - pci_write_config_byte(dev, COM_DEC, tmpbyte); - - /* Enable Low Pin Count interface */ - pci_read_config_word(dev, LPC_EN, &tmpword); - /* These seem to be set up at all times, - * just make sure it is properly set. - */ - switch(conf->cfg_base) { - case 0x04e: - tmpword |= 0x2000; - break; - case 0x02e: - tmpword |= 0x1000; - break; - case 0x062: - tmpword |= 0x0800; - break; - case 0x060: - tmpword |= 0x0400; - break; - default: - net_warn_ratelimited("Uncommon I/O base address: 0x%04x\n", - conf->cfg_base); - break; - } - tmpword &= 0xfffd; /* disable LPC COMB */ - tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ - pr_debug("LPC_EN (write): 0x%04x\n", tmpword); - pci_write_config_word(dev, LPC_EN, tmpword); - - /* - * Configure LPC DMA channel - * PCI_DMA_C bits: - * Bit 15-14: DMA channel 7 select - * Bit 13-12: DMA channel 6 select - * Bit 11-10: DMA channel 5 select - * Bit 9-8: Reserved - * Bit 7-6: DMA channel 3 select - * Bit 5-4: DMA channel 2 select - * Bit 3-2: DMA channel 1 select - * Bit 1-0: DMA channel 0 select - * 00 = Reserved value - * 01 = PC/PCI DMA - * 10 = Reserved value - * 11 = LPC I/F DMA - */ - pci_read_config_word(dev, PCI_DMA_C, &tmpword); - switch(conf->fir_dma) { - case 0x07: - tmpword |= 0xc000; - break; - case 0x06: - tmpword |= 0x3000; - break; - case 0x05: - tmpword |= 0x0c00; - break; - case 0x03: - tmpword |= 0x00c0; - break; - case 0x02: - tmpword |= 0x0030; - break; - case 0x01: - tmpword |= 0x000c; - break; - case 0x00: - tmpword |= 0x0003; - break; - default: - break; /* do not change settings */ - } - pr_debug("PCI_DMA_C (write): 0x%04x\n", tmpword); - pci_write_config_word(dev, PCI_DMA_C, tmpword); - - /* - * GEN2_DEC bits: - * Bit 15-4: Generic I/O range - * Bit 3-1: reserved (read as 0) - * Bit 0: enable GEN2 range on LPC I/F - */ - tmpword = conf->fir_io & 0xfff8; - tmpword |= 0x0001; - pr_debug("GEN2_DEC (write): 0x%04x\n", tmpword); - pci_write_config_word(dev, GEN2_DEC, tmpword); - - /* Pre-configure chip */ - return preconfigure_smsc_chip(conf); -} - -/* - * Pre-configure a certain port on the ALi 1533 bridge. - * This is based on reverse-engineering since ALi does not - * provide any data sheet for the 1533 chip. - */ -static void __init preconfigure_ali_port(struct pci_dev *dev, - unsigned short port) -{ - unsigned char reg; - /* These bits obviously control the different ports */ - unsigned char mask; - unsigned char tmpbyte; - - switch(port) { - case 0x0130: - case 0x0178: - reg = 0xb0; - mask = 0x80; - break; - case 0x03f8: - reg = 0xb4; - mask = 0x80; - break; - case 0x02f8: - reg = 0xb4; - mask = 0x30; - break; - case 0x02e8: - reg = 0xb4; - mask = 0x08; - break; - default: - net_err_ratelimited("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", - port); - return; - } - - pci_read_config_byte(dev, reg, &tmpbyte); - /* Turn on the right bits */ - tmpbyte |= mask; - pci_write_config_byte(dev, reg, tmpbyte); - net_info_ratelimited("Activated ALi 1533 ISA bridge port 0x%04x\n", - port); -} - -static int __init preconfigure_through_ali(struct pci_dev *dev, - struct - smsc_ircc_subsystem_configuration - *conf) -{ - /* Configure the two ports on the ALi 1533 */ - preconfigure_ali_port(dev, conf->sir_io); - preconfigure_ali_port(dev, conf->fir_io); - - /* Pre-configure chip */ - return preconfigure_smsc_chip(conf); -} - -static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, - unsigned short ircc_fir, - unsigned short ircc_sir, - unsigned char ircc_dma, - unsigned char ircc_irq) -{ - struct pci_dev *dev = NULL; - unsigned short ss_vendor = 0x0000; - unsigned short ss_device = 0x0000; - int ret = 0; - - for_each_pci_dev(dev) { - struct smsc_ircc_subsystem_configuration *conf; - - /* - * Cache the subsystem vendor/device: - * some manufacturers fail to set this for all components, - * so we save it in case there is just 0x0000 0x0000 on the - * device we want to check. - */ - if (dev->subsystem_vendor != 0x0000U) { - ss_vendor = dev->subsystem_vendor; - ss_device = dev->subsystem_device; - } - conf = subsystem_configurations; - for( ; conf->subvendor; conf++) { - if(conf->vendor == dev->vendor && - conf->device == dev->device && - conf->subvendor == ss_vendor && - /* Sometimes these are cached values */ - (conf->subdevice == ss_device || - conf->subdevice == 0xffff)) { - struct smsc_ircc_subsystem_configuration - tmpconf; - - memcpy(&tmpconf, conf, - sizeof(struct smsc_ircc_subsystem_configuration)); - - /* - * Override the default values with anything - * passed in as parameter - */ - if (ircc_cfg != 0) - tmpconf.cfg_base = ircc_cfg; - if (ircc_fir != 0) - tmpconf.fir_io = ircc_fir; - if (ircc_sir != 0) - tmpconf.sir_io = ircc_sir; - if (ircc_dma != DMA_INVAL) - tmpconf.fir_dma = ircc_dma; - if (ircc_irq != IRQ_INVAL) - tmpconf.fir_irq = ircc_irq; - - net_info_ratelimited("Detected unconfigured %s SMSC IrDA chip, pre-configuring device\n", - conf->name); - if (conf->preconfigure) - ret = conf->preconfigure(dev, &tmpconf); - else - ret = -ENODEV; - } - } - } - - return ret; -} -#endif // CONFIG_PCI - -/************************************************ - * - * Transceivers specific functions - * - ************************************************/ - - -/* - * Function smsc_ircc_set_transceiver_smsc_ircc_atc(fir_base, speed) - * - * Program transceiver through smsc-ircc ATC circuitry - * - */ - -static void smsc_ircc_set_transceiver_smsc_ircc_atc(int fir_base, u32 speed) -{ - unsigned long jiffies_now, jiffies_timeout; - u8 val; - - jiffies_now = jiffies; - jiffies_timeout = jiffies + SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES; - - /* ATC */ - register_bank(fir_base, 4); - outb((inb(fir_base + IRCC_ATC) & IRCC_ATC_MASK) | IRCC_ATC_nPROGREADY|IRCC_ATC_ENABLE, - fir_base + IRCC_ATC); - - while ((val = (inb(fir_base + IRCC_ATC) & IRCC_ATC_nPROGREADY)) && - !time_after(jiffies, jiffies_timeout)) - /* empty */; - - if (val) - net_warn_ratelimited("%s(): ATC: 0x%02x\n", - __func__, inb(fir_base + IRCC_ATC)); -} - -/* - * Function smsc_ircc_probe_transceiver_smsc_ircc_atc(fir_base) - * - * Probe transceiver smsc-ircc ATC circuitry - * - */ - -static int smsc_ircc_probe_transceiver_smsc_ircc_atc(int fir_base) -{ - return 0; -} - -/* - * Function smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(self, speed) - * - * Set transceiver - * - */ - -static void smsc_ircc_set_transceiver_smsc_ircc_fast_pin_select(int fir_base, u32 speed) -{ - u8 fast_mode; - - switch (speed) { - default: - case 576000 : - fast_mode = 0; - break; - case 1152000 : - case 4000000 : - fast_mode = IRCC_LCR_A_FAST; - break; - } - register_bank(fir_base, 0); - outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A); -} - -/* - * Function smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(fir_base) - * - * Probe transceiver - * - */ - -static int smsc_ircc_probe_transceiver_smsc_ircc_fast_pin_select(int fir_base) -{ - return 0; -} - -/* - * Function smsc_ircc_set_transceiver_toshiba_sat1800(fir_base, speed) - * - * Set transceiver - * - */ - -static void smsc_ircc_set_transceiver_toshiba_sat1800(int fir_base, u32 speed) -{ - u8 fast_mode; - - switch (speed) { - default: - case 576000 : - fast_mode = 0; - break; - case 1152000 : - case 4000000 : - fast_mode = /*IRCC_LCR_A_FAST |*/ IRCC_LCR_A_GP_DATA; - break; - - } - /* This causes an interrupt */ - register_bank(fir_base, 0); - outb((inb(fir_base + IRCC_LCR_A) & 0xbf) | fast_mode, fir_base + IRCC_LCR_A); -} - -/* - * Function smsc_ircc_probe_transceiver_toshiba_sat1800(fir_base) - * - * Probe transceiver - * - */ - -static int smsc_ircc_probe_transceiver_toshiba_sat1800(int fir_base) -{ - return 0; -} - - -module_init(smsc_ircc_init); -module_exit(smsc_ircc_cleanup); diff --git a/drivers/staging/irda/drivers/smsc-ircc2.h b/drivers/staging/irda/drivers/smsc-ircc2.h deleted file mode 100644 index 4829fa22cb29..000000000000 --- a/drivers/staging/irda/drivers/smsc-ircc2.h +++ /dev/null @@ -1,191 +0,0 @@ -/********************************************************************* - * - * Description: Definitions for the SMC IrCC chipset - * Status: Experimental. - * Author: Daniele Peri (peri@csai.unipa.it) - * - * Copyright (c) 2002 Daniele Peri - * All Rights Reserved. - * - * Based on smc-ircc.h: - * - * Copyright (c) 1999-2000, Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1998-1999, Thomas Davis (tadavis@jps.net> - * All Rights Reserved - * - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef SMSC_IRCC2_H -#define SMSC_IRCC2_H - -/* DMA modes needed */ -#define DMA_TX_MODE 0x08 /* Mem to I/O, ++, demand. */ -#define DMA_RX_MODE 0x04 /* I/O to mem, ++, demand. */ - -/* Master Control Register */ -#define IRCC_MASTER 0x07 -#define IRCC_MASTER_POWERDOWN 0x80 -#define IRCC_MASTER_RESET 0x40 -#define IRCC_MASTER_INT_EN 0x20 -#define IRCC_MASTER_ERROR_RESET 0x10 - -/* Register block 0 */ - -/* Interrupt Identification */ -#define IRCC_IIR 0x01 -#define IRCC_IIR_ACTIVE_FRAME 0x80 -#define IRCC_IIR_EOM 0x40 -#define IRCC_IIR_RAW_MODE 0x20 -#define IRCC_IIR_FIFO 0x10 - -/* Interrupt Enable */ -#define IRCC_IER 0x02 -#define IRCC_IER_ACTIVE_FRAME 0x80 -#define IRCC_IER_EOM 0x40 -#define IRCC_IER_RAW_MODE 0x20 -#define IRCC_IER_FIFO 0x10 - -/* Line Status Register */ -#define IRCC_LSR 0x03 -#define IRCC_LSR_UNDERRUN 0x80 -#define IRCC_LSR_OVERRUN 0x40 -#define IRCC_LSR_FRAME_ERROR 0x20 -#define IRCC_LSR_SIZE_ERROR 0x10 -#define IRCC_LSR_CRC_ERROR 0x80 -#define IRCC_LSR_FRAME_ABORT 0x40 - -/* Line Status Address Register */ -#define IRCC_LSAR 0x03 -#define IRCC_LSAR_ADDRESS_MASK 0x07 - -/* Line Control Register A */ -#define IRCC_LCR_A 0x04 -#define IRCC_LCR_A_FIFO_RESET 0x80 -#define IRCC_LCR_A_FAST 0x40 -#define IRCC_LCR_A_GP_DATA 0x20 -#define IRCC_LCR_A_RAW_TX 0x10 -#define IRCC_LCR_A_RAW_RX 0x08 -#define IRCC_LCR_A_ABORT 0x04 -#define IRCC_LCR_A_DATA_DONE 0x02 - -/* Line Control Register B */ -#define IRCC_LCR_B 0x05 -#define IRCC_LCR_B_SCE_DISABLED 0x00 -#define IRCC_LCR_B_SCE_TRANSMIT 0x40 -#define IRCC_LCR_B_SCE_RECEIVE 0x80 -#define IRCC_LCR_B_SCE_UNDEFINED 0xc0 -#define IRCC_LCR_B_SIP_ENABLE 0x20 -#define IRCC_LCR_B_BRICK_WALL 0x10 - -/* Bus Status Register */ -#define IRCC_BSR 0x06 -#define IRCC_BSR_NOT_EMPTY 0x80 -#define IRCC_BSR_FIFO_FULL 0x40 -#define IRCC_BSR_TIMEOUT 0x20 - -/* Register block 1 */ - -#define IRCC_FIFO_THRESHOLD 0x02 - -#define IRCC_SCE_CFGA 0x00 -#define IRCC_CFGA_AUX_IR 0x80 -#define IRCC_CFGA_HALF_DUPLEX 0x04 -#define IRCC_CFGA_TX_POLARITY 0x02 -#define IRCC_CFGA_RX_POLARITY 0x01 - -#define IRCC_CFGA_COM 0x00 -#define IRCC_SCE_CFGA_BLOCK_CTRL_BITS_MASK 0x87 -#define IRCC_CFGA_IRDA_SIR_A 0x08 -#define IRCC_CFGA_ASK_SIR 0x10 -#define IRCC_CFGA_IRDA_SIR_B 0x18 -#define IRCC_CFGA_IRDA_HDLC 0x20 -#define IRCC_CFGA_IRDA_4PPM 0x28 -#define IRCC_CFGA_CONSUMER 0x30 -#define IRCC_CFGA_RAW_IR 0x38 -#define IRCC_CFGA_OTHER 0x40 - -#define IRCC_IR_HDLC 0x04 -#define IRCC_IR_4PPM 0x01 -#define IRCC_IR_CONSUMER 0x02 - -#define IRCC_SCE_CFGB 0x01 -#define IRCC_CFGB_LOOPBACK 0x20 -#define IRCC_CFGB_LPBCK_TX_CRC 0x10 -#define IRCC_CFGB_NOWAIT 0x08 -#define IRCC_CFGB_STRING_MOVE 0x04 -#define IRCC_CFGB_DMA_BURST 0x02 -#define IRCC_CFGB_DMA_ENABLE 0x01 - -#define IRCC_CFGB_MUX_COM 0x00 -#define IRCC_CFGB_MUX_IR 0x40 -#define IRCC_CFGB_MUX_AUX 0x80 -#define IRCC_CFGB_MUX_INACTIVE 0xc0 - -/* Register block 3 - Identification Registers! */ -#define IRCC_ID_HIGH 0x00 /* 0x10 */ -#define IRCC_ID_LOW 0x01 /* 0xB8 */ -#define IRCC_CHIP_ID 0x02 /* 0xF1 */ -#define IRCC_VERSION 0x03 /* 0x01 */ -#define IRCC_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */ -#define IRCC_INTERFACE_DMA_MASK 0x0F /* low 4 = DMA, high 4 = IRQ */ -#define IRCC_INTERFACE_IRQ_MASK 0xF0 /* low 4 = DMA, high 4 = IRQ */ - -/* Register block 4 - IrDA */ -#define IRCC_CONTROL 0x00 -#define IRCC_BOF_COUNT_LO 0x01 /* Low byte */ -#define IRCC_BOF_COUNT_HI 0x00 /* High nibble (bit 0-3) */ -#define IRCC_BRICKWALL_CNT_LO 0x02 /* Low byte */ -#define IRCC_BRICKWALL_CNT_HI 0x03 /* High nibble (bit 4-7) */ -#define IRCC_TX_SIZE_LO 0x04 /* Low byte */ -#define IRCC_TX_SIZE_HI 0x03 /* High nibble (bit 0-3) */ -#define IRCC_RX_SIZE_HI 0x05 /* High nibble (bit 0-3) */ -#define IRCC_RX_SIZE_LO 0x06 /* Low byte */ - -#define IRCC_1152 0x80 -#define IRCC_CRC 0x40 - -/* Register block 5 - IrDA */ -#define IRCC_ATC 0x00 -#define IRCC_ATC_nPROGREADY 0x80 -#define IRCC_ATC_SPEED 0x40 -#define IRCC_ATC_ENABLE 0x20 -#define IRCC_ATC_MASK 0xE0 - - -#define IRCC_IRHALFDUPLEX_TIMEOUT 0x01 - -#define IRCC_SCE_TX_DELAY_TIMER 0x02 - -/* - * Other definitions - */ - -#define SMSC_IRCC2_MAX_SIR_SPEED 115200 -#define SMSC_IRCC2_FIR_CHIP_IO_EXTENT 8 -#define SMSC_IRCC2_SIR_CHIP_IO_EXTENT 8 -#define SMSC_IRCC2_FIFO_SIZE 16 -#define SMSC_IRCC2_FIFO_THRESHOLD 64 -/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ -#define SMSC_IRCC2_RX_BUFF_TRUESIZE 14384 -#define SMSC_IRCC2_TX_BUFF_TRUESIZE 14384 -#define SMSC_IRCC2_MIN_TURN_TIME 0x07 -#define SMSC_IRCC2_WINDOW_SIZE 0x07 -/* Maximum wait for hw transmitter to finish */ -#define SMSC_IRCC2_HW_TRANSMITTER_TIMEOUT_US 1000 /* 1 ms */ -/* Maximum wait for ATC transceiver programming to finish */ -#define SMSC_IRCC2_ATC_PROGRAMMING_TIMEOUT_JIFFIES 1 -#endif /* SMSC_IRCC2_H */ diff --git a/drivers/staging/irda/drivers/smsc-sio.h b/drivers/staging/irda/drivers/smsc-sio.h deleted file mode 100644 index 59e20e653ebe..000000000000 --- a/drivers/staging/irda/drivers/smsc-sio.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef SMSC_SIO_H -#define SMSC_SIO_H - -/****************************************** - Keys. They should work with every SMsC SIO - ******************************************/ - -#define SMSCSIO_CFGACCESSKEY 0x55 -#define SMSCSIO_CFGEXITKEY 0xaa - -/***************************** - * Generic SIO Flat (!?) * - *****************************/ - -/* Register 0x0d */ -#define SMSCSIOFLAT_DEVICEID_REG 0x0d - -/* Register 0x0c */ -#define SMSCSIOFLAT_UARTMODE0C_REG 0x0c -#define SMSCSIOFLAT_UART2MODE_MASK 0x38 -#define SMSCSIOFLAT_UART2MODE_VAL_COM 0x00 -#define SMSCSIOFLAT_UART2MODE_VAL_IRDA 0x08 -#define SMSCSIOFLAT_UART2MODE_VAL_ASKIR 0x10 - -/* Register 0x25 */ -#define SMSCSIOFLAT_UART2BASEADDR_REG 0x25 - -/* Register 0x2b */ -#define SMSCSIOFLAT_FIRBASEADDR_REG 0x2b - -/* Register 0x2c */ -#define SMSCSIOFLAT_FIRDMASELECT_REG 0x2c -#define SMSCSIOFLAT_FIRDMASELECT_MASK 0x0f - -/* Register 0x28 */ -#define SMSCSIOFLAT_UARTIRQSELECT_REG 0x28 -#define SMSCSIOFLAT_UART2IRQSELECT_MASK 0x0f -#define SMSCSIOFLAT_UART1IRQSELECT_MASK 0xf0 -#define SMSCSIOFLAT_UARTIRQSELECT_VAL_NONE 0x00 - - -/********************* - * LPC47N227 * - *********************/ - -#define LPC47N227_CFGACCESSKEY 0x55 -#define LPC47N227_CFGEXITKEY 0xaa - -/* Register 0x00 */ -#define LPC47N227_FDCPOWERVALIDCONF_REG 0x00 -#define LPC47N227_FDCPOWER_MASK 0x08 -#define LPC47N227_VALID_MASK 0x80 - -/* Register 0x02 */ -#define LPC47N227_UART12POWER_REG 0x02 -#define LPC47N227_UART1POWERDOWN_MASK 0x08 -#define LPC47N227_UART2POWERDOWN_MASK 0x80 - -/* Register 0x07 */ -#define LPC47N227_APMBOOTDRIVE_REG 0x07 -#define LPC47N227_PARPORT2AUTOPWRDOWN_MASK 0x10 /* auto power down on if set */ -#define LPC47N227_UART2AUTOPWRDOWN_MASK 0x20 /* auto power down on if set */ -#define LPC47N227_UART1AUTOPWRDOWN_MASK 0x40 /* auto power down on if set */ - -/* Register 0x0c */ -#define LPC47N227_UARTMODE0C_REG 0x0c -#define LPC47N227_UART2MODE_MASK 0x38 -#define LPC47N227_UART2MODE_VAL_COM 0x00 -#define LPC47N227_UART2MODE_VAL_IRDA 0x08 -#define LPC47N227_UART2MODE_VAL_ASKIR 0x10 - -/* Register 0x0d */ -#define LPC47N227_DEVICEID_REG 0x0d -#define LPC47N227_DEVICEID_DEFVAL 0x5a - -/* Register 0x0e */ -#define LPC47N227_REVISIONID_REG 0x0e - -/* Register 0x25 */ -#define LPC47N227_UART2BASEADDR_REG 0x25 - -/* Register 0x28 */ -#define LPC47N227_UARTIRQSELECT_REG 0x28 -#define LPC47N227_UART2IRQSELECT_MASK 0x0f -#define LPC47N227_UART1IRQSELECT_MASK 0xf0 -#define LPC47N227_UARTIRQSELECT_VAL_NONE 0x00 - -/* Register 0x2b */ -#define LPC47N227_FIRBASEADDR_REG 0x2b - -/* Register 0x2c */ -#define LPC47N227_FIRDMASELECT_REG 0x2c -#define LPC47N227_FIRDMASELECT_MASK 0x0f -#define LPC47N227_FIRDMASELECT_VAL_DMA1 0x01 /* 47n227 has three dma channels */ -#define LPC47N227_FIRDMASELECT_VAL_DMA2 0x02 -#define LPC47N227_FIRDMASELECT_VAL_DMA3 0x03 -#define LPC47N227_FIRDMASELECT_VAL_NONE 0x0f - - -#endif diff --git a/drivers/staging/irda/drivers/stir4200.c b/drivers/staging/irda/drivers/stir4200.c deleted file mode 100644 index ee2cb70b688d..000000000000 --- a/drivers/staging/irda/drivers/stir4200.c +++ /dev/null @@ -1,1134 +0,0 @@ -/***************************************************************************** -* -* Filename: stir4200.c -* Version: 0.4 -* Description: Irda SigmaTel USB Dongle -* Status: Experimental -* Author: Stephen Hemminger <shemminger@osdl.org> -* -* Based on earlier driver by Paul Stewart <stewart@parc.com> -* -* Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at> -* Copyright (C) 2001, Dag Brattli <dag@brattli.net> -* Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com> -* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> -* -* 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. -* -* 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. -* -*****************************************************************************/ - -/* - * This dongle does no framing, and requires polling to receive the - * data. The STIr4200 has bulk in and out endpoints just like - * usr-irda devices, but the data it sends and receives is raw; like - * irtty, it needs to call the wrap and unwrap functions to add and - * remove SOF/BOF and escape characters to/from the frame. - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> - -#include <linux/kernel.h> -#include <linux/sched/signal.h> -#include <linux/ktime.h> -#include <linux/types.h> -#include <linux/time.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/usb.h> -#include <linux/crc32.h> -#include <linux/kthread.h> -#include <linux/freezer.h> -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> -#include <net/irda/wrapper.h> -#include <net/irda/crc.h> -#include <asm/byteorder.h> -#include <asm/unaligned.h> - -MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>"); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver for SigmaTel STIr4200"); -MODULE_LICENSE("GPL"); - -static int qos_mtt_bits = 0x07; /* 1 ms or more */ -module_param(qos_mtt_bits, int, 0); -MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); - -static int rx_sensitivity = 1; /* FIR 0..4, SIR 0..6 */ -module_param(rx_sensitivity, int, 0); -MODULE_PARM_DESC(rx_sensitivity, "Set Receiver sensitivity (0-6, 0 is most sensitive)"); - -static int tx_power = 0; /* 0 = highest ... 3 = lowest */ -module_param(tx_power, int, 0); -MODULE_PARM_DESC(tx_power, "Set Transmitter power (0-3, 0 is highest power)"); - -#define STIR_IRDA_HEADER 4 -#define CTRL_TIMEOUT 100 /* milliseconds */ -#define TRANSMIT_TIMEOUT 200 /* milliseconds */ -#define STIR_FIFO_SIZE 4096 -#define FIFO_REGS_SIZE 3 - -enum FirChars { - FIR_CE = 0x7d, - FIR_XBOF = 0x7f, - FIR_EOF = 0x7e, -}; - -enum StirRequests { - REQ_WRITE_REG = 0x00, - REQ_READ_REG = 0x01, - REQ_READ_ROM = 0x02, - REQ_WRITE_SINGLE = 0x03, -}; - -/* Register offsets */ -enum StirRegs { - REG_RSVD=0, - REG_MODE, - REG_PDCLK, - REG_CTRL1, - REG_CTRL2, - REG_FIFOCTL, - REG_FIFOLSB, - REG_FIFOMSB, - REG_DPLL, - REG_IRDIG, - REG_TEST=15, -}; - -enum StirModeMask { - MODE_FIR = 0x80, - MODE_SIR = 0x20, - MODE_ASK = 0x10, - MODE_FASTRX = 0x08, - MODE_FFRSTEN = 0x04, - MODE_NRESET = 0x02, - MODE_2400 = 0x01, -}; - -enum StirPdclkMask { - PDCLK_4000000 = 0x02, - PDCLK_115200 = 0x09, - PDCLK_57600 = 0x13, - PDCLK_38400 = 0x1D, - PDCLK_19200 = 0x3B, - PDCLK_9600 = 0x77, - PDCLK_2400 = 0xDF, -}; - -enum StirCtrl1Mask { - CTRL1_SDMODE = 0x80, - CTRL1_RXSLOW = 0x40, - CTRL1_TXPWD = 0x10, - CTRL1_RXPWD = 0x08, - CTRL1_SRESET = 0x01, -}; - -enum StirCtrl2Mask { - CTRL2_SPWIDTH = 0x08, - CTRL2_REVID = 0x03, -}; - -enum StirFifoCtlMask { - FIFOCTL_DIR = 0x10, - FIFOCTL_CLR = 0x08, - FIFOCTL_EMPTY = 0x04, -}; - -enum StirDiagMask { - IRDIG_RXHIGH = 0x80, - IRDIG_RXLOW = 0x40, -}; - -enum StirTestMask { - TEST_PLLDOWN = 0x80, - TEST_LOOPIR = 0x40, - TEST_LOOPUSB = 0x20, - TEST_TSTENA = 0x10, - TEST_TSTOSC = 0x0F, -}; - -struct stir_cb { - struct usb_device *usbdev; /* init: probe_irda */ - struct net_device *netdev; /* network layer */ - struct irlap_cb *irlap; /* The link layer we are binded to */ - - struct qos_info qos; - unsigned speed; /* Current speed */ - - struct task_struct *thread; /* transmit thread */ - - struct sk_buff *tx_pending; - void *io_buf; /* transmit/receive buffer */ - __u8 *fifo_status; - - iobuff_t rx_buff; /* receive unwrap state machine */ - ktime_t rx_time; - int receiving; - struct urb *rx_urb; -}; - - -/* These are the currently known USB ids */ -static const struct usb_device_id dongles[] = { - /* SigmaTel, Inc, STIr4200 IrDA/USB Bridge */ - { USB_DEVICE(0x066f, 0x4200) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, dongles); - -/* Send control message to set dongle register */ -static int write_reg(struct stir_cb *stir, __u16 reg, __u8 value) -{ - struct usb_device *dev = stir->usbdev; - - pr_debug("%s: write reg %d = 0x%x\n", - stir->netdev->name, reg, value); - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - REQ_WRITE_SINGLE, - USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE, - value, reg, NULL, 0, - CTRL_TIMEOUT); -} - -/* Send control message to read multiple registers */ -static inline int read_reg(struct stir_cb *stir, __u16 reg, - __u8 *data, __u16 count) -{ - struct usb_device *dev = stir->usbdev; - - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - REQ_READ_REG, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, reg, data, count, - CTRL_TIMEOUT); -} - -static inline int isfir(u32 speed) -{ - return speed == 4000000; -} - -/* - * Prepare a FIR IrDA frame for transmission to the USB dongle. The - * FIR transmit frame is documented in the datasheet. It consists of - * a two byte 0x55 0xAA sequence, two little-endian length bytes, a - * sequence of exactly 16 XBOF bytes of 0x7E, two BOF bytes of 0x7E, - * then the data escaped as follows: - * - * 0x7D -> 0x7D 0x5D - * 0x7E -> 0x7D 0x5E - * 0x7F -> 0x7D 0x5F - * - * Then, 4 bytes of little endian (stuffed) FCS follow, then two - * trailing EOF bytes of 0x7E. - */ -static inline __u8 *stuff_fir(__u8 *p, __u8 c) -{ - switch(c) { - case 0x7d: - case 0x7e: - case 0x7f: - *p++ = 0x7d; - c ^= IRDA_TRANS; - /* fall through */ - default: - *p++ = c; - } - return p; -} - -/* Take raw data in skb and put it wrapped into buf */ -static unsigned wrap_fir_skb(const struct sk_buff *skb, __u8 *buf) -{ - __u8 *ptr = buf; - __u32 fcs = ~(crc32_le(~0, skb->data, skb->len)); - __u16 wraplen; - int i; - - /* Header */ - buf[0] = 0x55; - buf[1] = 0xAA; - - ptr = buf + STIR_IRDA_HEADER; - memset(ptr, 0x7f, 16); - ptr += 16; - - /* BOF */ - *ptr++ = 0x7e; - *ptr++ = 0x7e; - - /* Address / Control / Information */ - for (i = 0; i < skb->len; i++) - ptr = stuff_fir(ptr, skb->data[i]); - - /* FCS */ - ptr = stuff_fir(ptr, fcs & 0xff); - ptr = stuff_fir(ptr, (fcs >> 8) & 0xff); - ptr = stuff_fir(ptr, (fcs >> 16) & 0xff); - ptr = stuff_fir(ptr, (fcs >> 24) & 0xff); - - /* EOFs */ - *ptr++ = 0x7e; - *ptr++ = 0x7e; - - /* Total length, minus the header */ - wraplen = (ptr - buf) - STIR_IRDA_HEADER; - buf[2] = wraplen & 0xff; - buf[3] = (wraplen >> 8) & 0xff; - - return wraplen + STIR_IRDA_HEADER; -} - -static unsigned wrap_sir_skb(struct sk_buff *skb, __u8 *buf) -{ - __u16 wraplen; - - wraplen = async_wrap_skb(skb, buf + STIR_IRDA_HEADER, - STIR_FIFO_SIZE - STIR_IRDA_HEADER); - buf[0] = 0x55; - buf[1] = 0xAA; - buf[2] = wraplen & 0xff; - buf[3] = (wraplen >> 8) & 0xff; - - return wraplen + STIR_IRDA_HEADER; -} - -/* - * Frame is fully formed in the rx_buff so check crc - * and pass up to irlap - * setup for next receive - */ -static void fir_eof(struct stir_cb *stir) -{ - iobuff_t *rx_buff = &stir->rx_buff; - int len = rx_buff->len - 4; - struct sk_buff *skb, *nskb; - __u32 fcs; - - if (unlikely(len <= 0)) { - pr_debug("%s: short frame len %d\n", - stir->netdev->name, len); - - ++stir->netdev->stats.rx_errors; - ++stir->netdev->stats.rx_length_errors; - return; - } - - fcs = ~(crc32_le(~0, rx_buff->data, len)); - if (fcs != get_unaligned_le32(rx_buff->data + len)) { - pr_debug("crc error calc 0x%x len %d\n", fcs, len); - stir->netdev->stats.rx_errors++; - stir->netdev->stats.rx_crc_errors++; - return; - } - - /* if frame is short then just copy it */ - if (len < IRDA_RX_COPY_THRESHOLD) { - nskb = dev_alloc_skb(len + 1); - if (unlikely(!nskb)) { - ++stir->netdev->stats.rx_dropped; - return; - } - skb_reserve(nskb, 1); - skb = nskb; - skb_copy_to_linear_data(nskb, rx_buff->data, len); - } else { - nskb = dev_alloc_skb(rx_buff->truesize); - if (unlikely(!nskb)) { - ++stir->netdev->stats.rx_dropped; - return; - } - skb_reserve(nskb, 1); - skb = rx_buff->skb; - rx_buff->skb = nskb; - rx_buff->head = nskb->data; - } - - skb_put(skb, len); - - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - skb->dev = stir->netdev; - - netif_rx(skb); - - stir->netdev->stats.rx_packets++; - stir->netdev->stats.rx_bytes += len; - - rx_buff->data = rx_buff->head; - rx_buff->len = 0; -} - -/* Unwrap FIR stuffed data and bump it to IrLAP */ -static void stir_fir_chars(struct stir_cb *stir, - const __u8 *bytes, int len) -{ - iobuff_t *rx_buff = &stir->rx_buff; - int i; - - for (i = 0; i < len; i++) { - __u8 byte = bytes[i]; - - switch(rx_buff->state) { - case OUTSIDE_FRAME: - /* ignore garbage till start of frame */ - if (unlikely(byte != FIR_EOF)) - continue; - /* Now receiving frame */ - rx_buff->state = BEGIN_FRAME; - - /* Time to initialize receive buffer */ - rx_buff->data = rx_buff->head; - rx_buff->len = 0; - continue; - - case LINK_ESCAPE: - if (byte == FIR_EOF) { - pr_debug("%s: got EOF after escape\n", - stir->netdev->name); - goto frame_error; - } - rx_buff->state = INSIDE_FRAME; - byte ^= IRDA_TRANS; - break; - - case BEGIN_FRAME: - /* ignore multiple BOF/EOF */ - if (byte == FIR_EOF) - continue; - rx_buff->state = INSIDE_FRAME; - rx_buff->in_frame = TRUE; - - /* fall through */ - case INSIDE_FRAME: - switch(byte) { - case FIR_CE: - rx_buff->state = LINK_ESCAPE; - continue; - case FIR_XBOF: - /* 0x7f is not used in this framing */ - pr_debug("%s: got XBOF without escape\n", - stir->netdev->name); - goto frame_error; - case FIR_EOF: - rx_buff->state = OUTSIDE_FRAME; - rx_buff->in_frame = FALSE; - fir_eof(stir); - continue; - } - break; - } - - /* add byte to rx buffer */ - if (unlikely(rx_buff->len >= rx_buff->truesize)) { - pr_debug("%s: fir frame exceeds %d\n", - stir->netdev->name, rx_buff->truesize); - ++stir->netdev->stats.rx_over_errors; - goto error_recovery; - } - - rx_buff->data[rx_buff->len++] = byte; - continue; - - frame_error: - ++stir->netdev->stats.rx_frame_errors; - - error_recovery: - ++stir->netdev->stats.rx_errors; - rx_buff->state = OUTSIDE_FRAME; - rx_buff->in_frame = FALSE; - } -} - -/* Unwrap SIR stuffed data and bump it up to IrLAP */ -static void stir_sir_chars(struct stir_cb *stir, - const __u8 *bytes, int len) -{ - int i; - - for (i = 0; i < len; i++) - async_unwrap_char(stir->netdev, &stir->netdev->stats, - &stir->rx_buff, bytes[i]); -} - -static inline void unwrap_chars(struct stir_cb *stir, - const __u8 *bytes, int length) -{ - if (isfir(stir->speed)) - stir_fir_chars(stir, bytes, length); - else - stir_sir_chars(stir, bytes, length); -} - -/* Mode parameters for each speed */ -static const struct { - unsigned speed; - __u8 pdclk; -} stir_modes[] = { - { 2400, PDCLK_2400 }, - { 9600, PDCLK_9600 }, - { 19200, PDCLK_19200 }, - { 38400, PDCLK_38400 }, - { 57600, PDCLK_57600 }, - { 115200, PDCLK_115200 }, - { 4000000, PDCLK_4000000 }, -}; - - -/* - * Setup chip for speed. - * Called at startup to initialize the chip - * and on speed changes. - * - * Note: Write multiple registers doesn't appear to work - */ -static int change_speed(struct stir_cb *stir, unsigned speed) -{ - int i, err; - __u8 mode; - - for (i = 0; i < ARRAY_SIZE(stir_modes); ++i) { - if (speed == stir_modes[i].speed) - goto found; - } - - dev_warn(&stir->netdev->dev, "invalid speed %d\n", speed); - return -EINVAL; - - found: - pr_debug("speed change from %d to %d\n", stir->speed, speed); - - /* Reset modulator */ - err = write_reg(stir, REG_CTRL1, CTRL1_SRESET); - if (err) - goto out; - - /* Undocumented magic to tweak the DPLL */ - err = write_reg(stir, REG_DPLL, 0x15); - if (err) - goto out; - - /* Set clock */ - err = write_reg(stir, REG_PDCLK, stir_modes[i].pdclk); - if (err) - goto out; - - mode = MODE_NRESET | MODE_FASTRX; - if (isfir(speed)) - mode |= MODE_FIR | MODE_FFRSTEN; - else - mode |= MODE_SIR; - - if (speed == 2400) - mode |= MODE_2400; - - err = write_reg(stir, REG_MODE, mode); - if (err) - goto out; - - /* This resets TEMIC style transceiver if any. */ - err = write_reg(stir, REG_CTRL1, - CTRL1_SDMODE | (tx_power & 3) << 1); - if (err) - goto out; - - err = write_reg(stir, REG_CTRL1, (tx_power & 3) << 1); - if (err) - goto out; - - /* Reset sensitivity */ - err = write_reg(stir, REG_CTRL2, (rx_sensitivity & 7) << 5); - out: - stir->speed = speed; - return err; -} - -/* - * Called from net/core when new frame is available. - */ -static netdev_tx_t stir_hard_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct stir_cb *stir = netdev_priv(netdev); - - netif_stop_queue(netdev); - - /* the IRDA wrapping routines don't deal with non linear skb */ - SKB_LINEAR_ASSERT(skb); - - skb = xchg(&stir->tx_pending, skb); - wake_up_process(stir->thread); - - /* this should never happen unless stop/wakeup problem */ - if (unlikely(skb)) { - WARN_ON(1); - dev_kfree_skb(skb); - } - - return NETDEV_TX_OK; -} - -/* - * Wait for the transmit FIFO to have space for next data - * - * If space < 0 then wait till FIFO completely drains. - * FYI: can take up to 13 seconds at 2400baud. - */ -static int fifo_txwait(struct stir_cb *stir, int space) -{ - int err; - unsigned long count, status; - unsigned long prev_count = 0x1fff; - - /* Read FIFO status and count */ - for (;; prev_count = count) { - err = read_reg(stir, REG_FIFOCTL, stir->fifo_status, - FIFO_REGS_SIZE); - if (unlikely(err != FIFO_REGS_SIZE)) { - dev_warn(&stir->netdev->dev, - "FIFO register read error: %d\n", err); - - return err; - } - - status = stir->fifo_status[0]; - count = (unsigned)(stir->fifo_status[2] & 0x1f) << 8 - | stir->fifo_status[1]; - - pr_debug("fifo status 0x%lx count %lu\n", status, count); - - /* is fifo receiving already, or empty */ - if (!(status & FIFOCTL_DIR) || - (status & FIFOCTL_EMPTY)) - return 0; - - if (signal_pending(current)) - return -EINTR; - - /* shutting down? */ - if (!netif_running(stir->netdev) || - !netif_device_present(stir->netdev)) - return -ESHUTDOWN; - - /* only waiting for some space */ - if (space >= 0 && STIR_FIFO_SIZE - 4 > space + count) - return 0; - - /* queue confused */ - if (prev_count < count) - break; - - /* estimate transfer time for remaining chars */ - msleep((count * 8000) / stir->speed); - } - - err = write_reg(stir, REG_FIFOCTL, FIFOCTL_CLR); - if (err) - return err; - err = write_reg(stir, REG_FIFOCTL, 0); - if (err) - return err; - - return 0; -} - - -/* Wait for turnaround delay before starting transmit. */ -static void turnaround_delay(const struct stir_cb *stir, long us) -{ - long ticks; - - if (us <= 0) - return; - - us -= ktime_us_delta(ktime_get(), stir->rx_time); - - if (us < 10) - return; - - ticks = us / (1000000 / HZ); - if (ticks > 0) - schedule_timeout_interruptible(1 + ticks); - else - udelay(us); -} - -/* - * Start receiver by submitting a request to the receive pipe. - * If nothing is available it will return after rx_interval. - */ -static int receive_start(struct stir_cb *stir) -{ - /* reset state */ - stir->receiving = 1; - - stir->rx_buff.in_frame = FALSE; - stir->rx_buff.state = OUTSIDE_FRAME; - - stir->rx_urb->status = 0; - return usb_submit_urb(stir->rx_urb, GFP_KERNEL); -} - -/* Stop all pending receive Urb's */ -static void receive_stop(struct stir_cb *stir) -{ - stir->receiving = 0; - usb_kill_urb(stir->rx_urb); - - if (stir->rx_buff.in_frame) - stir->netdev->stats.collisions++; -} -/* - * Wrap data in socket buffer and send it. - */ -static void stir_send(struct stir_cb *stir, struct sk_buff *skb) -{ - unsigned wraplen; - int first_frame = 0; - - /* if receiving, need to turnaround */ - if (stir->receiving) { - receive_stop(stir); - turnaround_delay(stir, irda_get_mtt(skb)); - first_frame = 1; - } - - if (isfir(stir->speed)) - wraplen = wrap_fir_skb(skb, stir->io_buf); - else - wraplen = wrap_sir_skb(skb, stir->io_buf); - - /* check for space available in fifo */ - if (!first_frame) - fifo_txwait(stir, wraplen); - - stir->netdev->stats.tx_packets++; - stir->netdev->stats.tx_bytes += skb->len; - netif_trans_update(stir->netdev); - pr_debug("send %d (%d)\n", skb->len, wraplen); - - if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1), - stir->io_buf, wraplen, - NULL, TRANSMIT_TIMEOUT)) - stir->netdev->stats.tx_errors++; -} - -/* - * Transmit state machine thread - */ -static int stir_transmit_thread(void *arg) -{ - struct stir_cb *stir = arg; - struct net_device *dev = stir->netdev; - struct sk_buff *skb; - - while (!kthread_should_stop()) { -#ifdef CONFIG_PM - /* if suspending, then power off and wait */ - if (unlikely(freezing(current))) { - if (stir->receiving) - receive_stop(stir); - else - fifo_txwait(stir, -1); - - write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD); - - try_to_freeze(); - - if (change_speed(stir, stir->speed)) - break; - } -#endif - - /* if something to send? */ - skb = xchg(&stir->tx_pending, NULL); - if (skb) { - unsigned new_speed = irda_get_next_speed(skb); - netif_wake_queue(dev); - - if (skb->len > 0) - stir_send(stir, skb); - dev_kfree_skb(skb); - - if ((new_speed != -1) && (stir->speed != new_speed)) { - if (fifo_txwait(stir, -1) || - change_speed(stir, new_speed)) - break; - } - continue; - } - - /* nothing to send? start receiving */ - if (!stir->receiving && - irda_device_txqueue_empty(dev)) { - /* Wait otherwise chip gets confused. */ - if (fifo_txwait(stir, -1)) - break; - - if (unlikely(receive_start(stir))) { - if (net_ratelimit()) - dev_info(&dev->dev, - "%s: receive usb submit failed\n", - stir->netdev->name); - stir->receiving = 0; - msleep(10); - continue; - } - } - - /* sleep if nothing to send */ - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - - } - return 0; -} - - -/* - * USB bulk receive completion callback. - * Wakes up every ms (usb round trip) with wrapped - * data. - */ -static void stir_rcv_irq(struct urb *urb) -{ - struct stir_cb *stir = urb->context; - int err; - - /* in process of stopping, just drop data */ - if (!netif_running(stir->netdev)) - return; - - /* unlink, shutdown, unplug, other nasties */ - if (urb->status != 0) - return; - - if (urb->actual_length > 0) { - pr_debug("receive %d\n", urb->actual_length); - unwrap_chars(stir, urb->transfer_buffer, - urb->actual_length); - - stir->rx_time = ktime_get(); - } - - /* kernel thread is stopping receiver don't resubmit */ - if (!stir->receiving) - return; - - /* resubmit existing urb */ - err = usb_submit_urb(urb, GFP_ATOMIC); - - /* in case of error, the kernel thread will restart us */ - if (err) { - dev_warn(&stir->netdev->dev, "usb receive submit error: %d\n", - err); - stir->receiving = 0; - wake_up_process(stir->thread); - } -} - -/* - * Function stir_net_open (dev) - * - * Network device is taken up. Usually this is done by "ifconfig irda0 up" - */ -static int stir_net_open(struct net_device *netdev) -{ - struct stir_cb *stir = netdev_priv(netdev); - int err; - char hwname[16]; - - err = usb_clear_halt(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1)); - if (err) - goto err_out1; - err = usb_clear_halt(stir->usbdev, usb_rcvbulkpipe(stir->usbdev, 2)); - if (err) - goto err_out1; - - err = change_speed(stir, 9600); - if (err) - goto err_out1; - - err = -ENOMEM; - - /* Initialize for SIR/FIR to copy data directly into skb. */ - stir->receiving = 0; - stir->rx_buff.truesize = IRDA_SKB_MAX_MTU; - stir->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); - if (!stir->rx_buff.skb) - goto err_out1; - - skb_reserve(stir->rx_buff.skb, 1); - stir->rx_buff.head = stir->rx_buff.skb->data; - stir->rx_time = ktime_get(); - - stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!stir->rx_urb) - goto err_out2; - - stir->io_buf = kmalloc(STIR_FIFO_SIZE, GFP_KERNEL); - if (!stir->io_buf) - goto err_out3; - - usb_fill_bulk_urb(stir->rx_urb, stir->usbdev, - usb_rcvbulkpipe(stir->usbdev, 2), - stir->io_buf, STIR_FIFO_SIZE, - stir_rcv_irq, stir); - - stir->fifo_status = kmalloc(FIFO_REGS_SIZE, GFP_KERNEL); - if (!stir->fifo_status) - goto err_out4; - - /* - * Now that everything should be initialized properly, - * Open new IrLAP layer instance to take care of us... - * Note : will send immediately a speed change... - */ - sprintf(hwname, "usb#%d", stir->usbdev->devnum); - stir->irlap = irlap_open(netdev, &stir->qos, hwname); - if (!stir->irlap) { - dev_err(&stir->usbdev->dev, "irlap_open failed\n"); - goto err_out5; - } - - /** Start kernel thread for transmit. */ - stir->thread = kthread_run(stir_transmit_thread, stir, - "%s", stir->netdev->name); - if (IS_ERR(stir->thread)) { - err = PTR_ERR(stir->thread); - dev_err(&stir->usbdev->dev, "unable to start kernel thread\n"); - goto err_out6; - } - - netif_start_queue(netdev); - - return 0; - - err_out6: - irlap_close(stir->irlap); - err_out5: - kfree(stir->fifo_status); - err_out4: - kfree(stir->io_buf); - err_out3: - usb_free_urb(stir->rx_urb); - err_out2: - kfree_skb(stir->rx_buff.skb); - err_out1: - return err; -} - -/* - * Function stir_net_close (stir) - * - * Network device is taken down. Usually this is done by - * "ifconfig irda0 down" - */ -static int stir_net_close(struct net_device *netdev) -{ - struct stir_cb *stir = netdev_priv(netdev); - - /* Stop transmit processing */ - netif_stop_queue(netdev); - - /* Kill transmit thread */ - kthread_stop(stir->thread); - kfree(stir->fifo_status); - - /* Mop up receive urb's */ - usb_kill_urb(stir->rx_urb); - - kfree(stir->io_buf); - usb_free_urb(stir->rx_urb); - kfree_skb(stir->rx_buff.skb); - - /* Stop and remove instance of IrLAP */ - if (stir->irlap) - irlap_close(stir->irlap); - - stir->irlap = NULL; - - return 0; -} - -/* - * IOCTLs : Extra out-of-band network commands... - */ -static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct stir_cb *stir = netdev_priv(netdev); - int ret = 0; - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the device is still there */ - if (netif_device_present(stir->netdev)) - ret = change_speed(stir, irq->ifr_baudrate); - break; - - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - /* Check if the IrDA stack is still there */ - if (netif_running(stir->netdev)) - irda_device_set_media_busy(stir->netdev, TRUE); - break; - - case SIOCGRECEIVING: - /* Only approximately true */ - irq->ifr_receiving = stir->receiving; - break; - - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -static const struct net_device_ops stir_netdev_ops = { - .ndo_open = stir_net_open, - .ndo_stop = stir_net_close, - .ndo_start_xmit = stir_hard_xmit, - .ndo_do_ioctl = stir_net_ioctl, -}; - -/* - * This routine is called by the USB subsystem for each new device - * in the system. We need to check if the device is ours, and in - * this case start handling it. - * Note : it might be worth protecting this function by a global - * spinlock... Or not, because maybe USB already deal with that... - */ -static int stir_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct stir_cb *stir = NULL; - struct net_device *net; - int ret = -ENOMEM; - - /* Allocate network device container. */ - net = alloc_irdadev(sizeof(*stir)); - if(!net) - goto err_out1; - - SET_NETDEV_DEV(net, &intf->dev); - stir = netdev_priv(net); - stir->netdev = net; - stir->usbdev = dev; - - ret = usb_reset_configuration(dev); - if (ret != 0) { - dev_err(&intf->dev, "usb reset configuration failed\n"); - goto err_out2; - } - - printk(KERN_INFO "SigmaTel STIr4200 IRDA/USB found at address %d, " - "Vendor: %x, Product: %x\n", - dev->devnum, le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&stir->qos); - - /* That's the Rx capability. */ - stir->qos.baud_rate.bits &= IR_2400 | IR_9600 | IR_19200 | - IR_38400 | IR_57600 | IR_115200 | - (IR_4000000 << 8); - stir->qos.min_turn_time.bits &= qos_mtt_bits; - irda_qos_bits_to_value(&stir->qos); - - /* Override the network functions we need to use */ - net->netdev_ops = &stir_netdev_ops; - - ret = register_netdev(net); - if (ret != 0) - goto err_out2; - - dev_info(&intf->dev, "IrDA: Registered SigmaTel device %s\n", - net->name); - - usb_set_intfdata(intf, stir); - - return 0; - -err_out2: - free_netdev(net); -err_out1: - return ret; -} - -/* - * The current device is removed, the USB layer tell us to shut it down... - */ -static void stir_disconnect(struct usb_interface *intf) -{ - struct stir_cb *stir = usb_get_intfdata(intf); - - if (!stir) - return; - - unregister_netdev(stir->netdev); - free_netdev(stir->netdev); - - usb_set_intfdata(intf, NULL); -} - -#ifdef CONFIG_PM -/* USB suspend, so power off the transmitter/receiver */ -static int stir_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct stir_cb *stir = usb_get_intfdata(intf); - - netif_device_detach(stir->netdev); - return 0; -} - -/* Coming out of suspend, so reset hardware */ -static int stir_resume(struct usb_interface *intf) -{ - struct stir_cb *stir = usb_get_intfdata(intf); - - netif_device_attach(stir->netdev); - - /* receiver restarted when send thread wakes up */ - return 0; -} -#endif - -/* - * USB device callbacks - */ -static struct usb_driver irda_driver = { - .name = "stir4200", - .probe = stir_probe, - .disconnect = stir_disconnect, - .id_table = dongles, -#ifdef CONFIG_PM - .suspend = stir_suspend, - .resume = stir_resume, -#endif -}; - -module_usb_driver(irda_driver); diff --git a/drivers/staging/irda/drivers/tekram-sir.c b/drivers/staging/irda/drivers/tekram-sir.c deleted file mode 100644 index 9dcf0c103b9d..000000000000 --- a/drivers/staging/irda/drivers/tekram-sir.c +++ /dev/null @@ -1,225 +0,0 @@ -/********************************************************************* - * - * Filename: tekram.c - * Version: 1.3 - * Description: Implementation of the Tekram IrMate IR-210B dongle - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Sun Oct 27 22:02:38 2002 - * Modified by: Martin Diehl <mad@mdiehl.de> - * - * Copyright (c) 1998-1999 Dag Brattli, - * Copyright (c) 2002 Martin Diehl, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -static int tekram_delay = 150; /* default is 150 ms */ -module_param(tekram_delay, int, 0); -MODULE_PARM_DESC(tekram_delay, "tekram dongle write complete delay"); - -static int tekram_open(struct sir_dev *); -static int tekram_close(struct sir_dev *); -static int tekram_change_speed(struct sir_dev *, unsigned); -static int tekram_reset(struct sir_dev *); - -#define TEKRAM_115200 0x00 -#define TEKRAM_57600 0x01 -#define TEKRAM_38400 0x02 -#define TEKRAM_19200 0x03 -#define TEKRAM_9600 0x04 - -#define TEKRAM_PW 0x10 /* Pulse select bit */ - -static struct dongle_driver tekram = { - .owner = THIS_MODULE, - .driver_name = "Tekram IR-210B", - .type = IRDA_TEKRAM_DONGLE, - .open = tekram_open, - .close = tekram_close, - .reset = tekram_reset, - .set_speed = tekram_change_speed, -}; - -static int __init tekram_sir_init(void) -{ - if (tekram_delay < 1 || tekram_delay > 500) - tekram_delay = 200; - pr_debug("%s - using %d ms delay\n", - tekram.driver_name, tekram_delay); - return irda_register_dongle(&tekram); -} - -static void __exit tekram_sir_cleanup(void) -{ - irda_unregister_dongle(&tekram); -} - -static int tekram_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int tekram_close(struct sir_dev *dev) -{ - /* Power off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function tekram_change_speed (dev, state, speed) - * - * Set the speed for the Tekram IRMate 210 type dongle. Warning, this - * function must be called with a process context! - * - * Algorithm - * 1. clear DTR - * 2. set RTS, and wait at least 7 us - * 3. send Control Byte to the IR-210 through TXD to set new baud rate - * wait until the stop bit of Control Byte is sent (for 9600 baud rate, - * it takes about 100 msec) - * - * [oops, why 100 msec? sending 1 byte (10 bits) takes 1.05 msec - * - is this probably to compensate for delays in tty layer?] - * - * 5. clear RTS (return to NORMAL Operation) - * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here - * after - */ - -#define TEKRAM_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) - -static int tekram_change_speed(struct sir_dev *dev, unsigned speed) -{ - unsigned state = dev->fsm.substate; - unsigned delay = 0; - u8 byte; - static int ret = 0; - - switch(state) { - case SIRDEV_STATE_DONGLE_SPEED: - - switch (speed) { - default: - speed = 9600; - ret = -EINVAL; - /* fall thru */ - case 9600: - byte = TEKRAM_PW|TEKRAM_9600; - break; - case 19200: - byte = TEKRAM_PW|TEKRAM_19200; - break; - case 38400: - byte = TEKRAM_PW|TEKRAM_38400; - break; - case 57600: - byte = TEKRAM_PW|TEKRAM_57600; - break; - case 115200: - byte = TEKRAM_115200; - break; - } - - /* Set DTR, Clear RTS */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - - /* Wait at least 7us */ - udelay(14); - - /* Write control byte */ - sirdev_raw_write(dev, &byte, 1); - - dev->speed = speed; - - state = TEKRAM_STATE_WAIT_SPEED; - delay = tekram_delay; - break; - - case TEKRAM_STATE_WAIT_SPEED: - /* Set DTR, Set RTS */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - udelay(50); - break; - - default: - net_err_ratelimited("%s - undefined state %d\n", - __func__, state); - ret = -EINVAL; - break; - } - - dev->fsm.substate = state; - return (delay > 0) ? delay : ret; -} - -/* - * Function tekram_reset (driver) - * - * This function resets the tekram dongle. Warning, this function - * must be called with a process context!! - * - * Algorithm: - * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 ) - * 1. clear RTS - * 2. set DTR, and wait at least 1 ms - * 3. clear DTR to SPACE state, wait at least 50 us for further - * operation - */ - -static int tekram_reset(struct sir_dev *dev) -{ - /* Clear DTR, Set RTS */ - sirdev_set_dtr_rts(dev, FALSE, TRUE); - - /* Should sleep 1 ms */ - msleep(1); - - /* Set DTR, Set RTS */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Wait at least 50 us */ - udelay(75); - - dev->speed = 9600; - - return 0; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-0"); /* IRDA_TEKRAM_DONGLE */ - -module_init(tekram_sir_init); -module_exit(tekram_sir_cleanup); diff --git a/drivers/staging/irda/drivers/toim3232-sir.c b/drivers/staging/irda/drivers/toim3232-sir.c deleted file mode 100644 index b977d6d33e74..000000000000 --- a/drivers/staging/irda/drivers/toim3232-sir.c +++ /dev/null @@ -1,358 +0,0 @@ -/********************************************************************* - * - * Filename: toim3232-sir.c - * Version: 1.0 - * Description: Implementation of dongles based on the Vishay/Temic - * TOIM3232 SIR Endec chipset. Currently only the - * IRWave IR320ST-2 is tested, although it should work - * with any TOIM3232 or TOIM4232 chipset based RS232 - * dongle with minimal modification. - * Based heavily on the Tekram driver (tekram.c), - * with thanks to Dag Brattli and Martin Diehl. - * Status: Experimental. - * Author: David Basden <davidb-irda@rcpt.to> - * Created at: Thu Feb 09 23:47:32 2006 - * - * Copyright (c) 2006 David Basden. - * Copyright (c) 1998-1999 Dag Brattli, - * Copyright (c) 2002 Martin Diehl, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -/* - * This driver has currently only been tested on the IRWave IR320ST-2 - * - * PROTOCOL: - * - * The protocol for talking to the TOIM3232 is quite easy, and is - * designed to interface with RS232 with only level convertors. The - * BR/~D line on the chip is brought high to signal 'command mode', - * where a command byte is sent to select the baudrate of the RS232 - * interface and the pulse length of the IRDA output. When BR/~D - * is brought low, the dongle then changes to the selected baudrate, - * and the RS232 interface is used for data until BR/~D is brought - * high again. The initial speed for the TOIMx323 after RESET is - * 9600 baud. The baudrate for command-mode is the last selected - * baud-rate, or 9600 after a RESET. - * - * The dongle I have (below) adds some extra hardware on the front end, - * but this is mostly directed towards pariasitic power from the RS232 - * line rather than changing very much about how to communicate with - * the TOIM3232. - * - * The protocol to talk to the TOIM4232 chipset seems to be almost - * identical to the TOIM3232 (and the 4232 datasheet is more detailed) - * so this code will probably work on that as well, although I haven't - * tested it on that hardware. - * - * Target dongle variations that might be common: - * - * DTR and RTS function: - * The data sheet for the 4232 has a sample implementation that hooks the - * DTR and RTS lines to the RESET and BaudRate/~Data lines of the - * chip (through line-converters). Given both DTR and RTS would have to - * be held low in normal operation, and the TOIMx232 requires +5V to - * signal ground, most dongle designers would almost certainly choose - * an implementation that kept at least one of DTR or RTS high in - * normal operation to provide power to the dongle, but will likely - * vary between designs. - * - * User specified command bits: - * There are two user-controllable output lines from the TOIMx232 that - * can be set low or high by setting the appropriate bits in the - * high-nibble of the command byte (when setting speed and pulse length). - * These might be used to switch on and off added hardware or extra - * dongle features. - * - * - * Target hardware: IRWave IR320ST-2 - * - * The IRWave IR320ST-2 is a simple dongle based on the Vishay/Temic - * TOIM3232 SIR Endec and the Vishay/Temic TFDS4500 SIR IRDA transceiver. - * It uses a hex inverter and some discrete components to buffer and - * line convert the RS232 down to 5V. - * - * The dongle is powered through a voltage regulator, fed by a large - * capacitor. To switch the dongle on, DTR is brought high to charge - * the capacitor and drive the voltage regulator. DTR isn't associated - * with any control lines on the TOIM3232. Parisitic power is also taken - * from the RTS, TD and RD lines when brought high, but through resistors. - * When DTR is low, the circuit might lose power even with RTS high. - * - * RTS is inverted and attached to the BR/~D input pin. When RTS - * is high, BR/~D is low, and the TOIM3232 is in the normal 'data' mode. - * RTS is brought low, BR/~D is high, and the TOIM3232 is in 'command - * mode'. - * - * For some unknown reason, the RESET line isn't actually connected - * to anything. This means to reset the dongle to get it to a known - * state (9600 baud) you must drop DTR and RTS low, wait for the power - * capacitor to discharge, and then bring DTR (and RTS for data mode) - * high again, and wait for the capacitor to charge, the power supply - * to stabilise, and the oscillator clock to stabilise. - * - * Fortunately, if the current baudrate is known, the chipset can - * easily change speed by entering command mode without having to - * reset the dongle first. - * - * Major Components: - * - * - Vishay/Temic TOIM3232 SIR Endec to change RS232 pulse timings - * to IRDA pulse timings - * - 3.6864MHz crystal to drive TOIM3232 clock oscillator - * - DM74lS04M Inverting Hex line buffer for RS232 input buffering - * and level conversion - * - PJ2951AC 150mA voltage regulator - * - Vishay/Temic TFDS4500 SIR IRDA front-end transceiver - * - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/sched.h> - -#include <net/irda/irda.h> - -#include "sir-dev.h" - -static int toim3232delay = 150; /* default is 150 ms */ -module_param(toim3232delay, int, 0); -MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay"); - -static int toim3232_open(struct sir_dev *); -static int toim3232_close(struct sir_dev *); -static int toim3232_change_speed(struct sir_dev *, unsigned); -static int toim3232_reset(struct sir_dev *); - -#define TOIM3232_115200 0x00 -#define TOIM3232_57600 0x01 -#define TOIM3232_38400 0x02 -#define TOIM3232_19200 0x03 -#define TOIM3232_9600 0x06 -#define TOIM3232_2400 0x0A - -#define TOIM3232_PW 0x10 /* Pulse select bit */ - -static struct dongle_driver toim3232 = { - .owner = THIS_MODULE, - .driver_name = "Vishay TOIM3232", - .type = IRDA_TOIM3232_DONGLE, - .open = toim3232_open, - .close = toim3232_close, - .reset = toim3232_reset, - .set_speed = toim3232_change_speed, -}; - -static int __init toim3232_sir_init(void) -{ - if (toim3232delay < 1 || toim3232delay > 500) - toim3232delay = 200; - pr_debug("%s - using %d ms delay\n", - toim3232.driver_name, toim3232delay); - return irda_register_dongle(&toim3232); -} - -static void __exit toim3232_sir_cleanup(void) -{ - irda_unregister_dongle(&toim3232); -} - -static int toim3232_open(struct sir_dev *dev) -{ - struct qos_info *qos = &dev->qos; - - /* Pull the lines high to start with. - * - * For the IR320ST-2, we need to charge the main supply capacitor to - * switch the device on. We keep DTR high throughout to do this. - * When RTS, TD and RD are high, they will also trickle-charge the - * cap. RTS is high for data transmission, and low for baud rate select. - * -- DGB - */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* The TOI3232 supports many speeds between 1200bps and 115000bps. - * We really only care about those supported by the IRDA spec, but - * 38400 seems to be implemented in many places */ - qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - - /* From the tekram driver. Not sure what a reasonable value is -- DGB */ - qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ - irda_qos_bits_to_value(qos); - - /* irda thread waits 50 msec for power settling */ - - return 0; -} - -static int toim3232_close(struct sir_dev *dev) -{ - /* Power off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - return 0; -} - -/* - * Function toim3232change_speed (dev, state, speed) - * - * Set the speed for the TOIM3232 based dongle. Warning, this - * function must be called with a process context! - * - * Algorithm - * 1. keep DTR high but clear RTS to bring into baud programming mode - * 2. wait at least 7us to enter programming mode - * 3. send control word to set baud rate and timing - * 4. wait at least 1us - * 5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver) - * 6. should take effect immediately (although probably worth waiting) - */ - -#define TOIM3232_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) - -static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) -{ - unsigned state = dev->fsm.substate; - unsigned delay = 0; - u8 byte; - static int ret = 0; - - switch(state) { - case SIRDEV_STATE_DONGLE_SPEED: - - /* Figure out what we are going to send as a control byte */ - switch (speed) { - case 2400: - byte = TOIM3232_PW|TOIM3232_2400; - break; - default: - speed = 9600; - ret = -EINVAL; - /* fall thru */ - case 9600: - byte = TOIM3232_PW|TOIM3232_9600; - break; - case 19200: - byte = TOIM3232_PW|TOIM3232_19200; - break; - case 38400: - byte = TOIM3232_PW|TOIM3232_38400; - break; - case 57600: - byte = TOIM3232_PW|TOIM3232_57600; - break; - case 115200: - byte = TOIM3232_115200; - break; - } - - /* Set DTR, Clear RTS: Go into baud programming mode */ - sirdev_set_dtr_rts(dev, TRUE, FALSE); - - /* Wait at least 7us */ - udelay(14); - - /* Write control byte */ - sirdev_raw_write(dev, &byte, 1); - - dev->speed = speed; - - state = TOIM3232_STATE_WAIT_SPEED; - delay = toim3232delay; - break; - - case TOIM3232_STATE_WAIT_SPEED: - /* Have transmitted control byte * Wait for 'at least 1us' */ - udelay(14); - - /* Set DTR, Set RTS: Go into normal data mode */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Wait (TODO: check this is needed) */ - udelay(50); - break; - - default: - printk(KERN_ERR "%s - undefined state %d\n", __func__, state); - ret = -EINVAL; - break; - } - - dev->fsm.substate = state; - return (delay > 0) ? delay : ret; -} - -/* - * Function toim3232reset (driver) - * - * This function resets the toim3232 dongle. Warning, this function - * must be called with a process context!! - * - * What we should do is: - * 0. Pull RESET high - * 1. Wait for at least 7us - * 2. Pull RESET low - * 3. Wait for at least 7us - * 4. Pull BR/~D high - * 5. Wait for at least 7us - * 6. Send control byte to set baud rate - * 7. Wait at least 1us after stop bit - * 8. Pull BR/~D low - * 9. Should then be in data mode - * - * Because the IR320ST-2 doesn't have the RESET line connected for some reason, - * we'll have to do something else. - * - * The default speed after a RESET is 9600, so lets try just bringing it up in - * data mode after switching it off, waiting for the supply capacitor to - * discharge, and then switch it back on. This isn't actually pulling RESET - * high, but it seems to have the same effect. - * - * This behaviour will probably work on dongles that have the RESET line connected, - * but if not, add a flag for the IR320ST-2, and implment the above-listed proper - * behaviour. - * - * RTS is inverted and then fed to BR/~D, so to put it in programming mode, we - * need to have pull RTS low - */ - -static int toim3232_reset(struct sir_dev *dev) -{ - /* Switch off both DTR and RTS to switch off dongle */ - sirdev_set_dtr_rts(dev, FALSE, FALSE); - - /* Should sleep a while. This might be evil doing it this way.*/ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(50)); - - /* Set DTR, Set RTS (data mode) */ - sirdev_set_dtr_rts(dev, TRUE, TRUE); - - /* Wait at least 10 ms for power to stabilize again */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(10)); - - /* Speed should now be 9600 */ - dev->speed = 9600; - - return 0; -} - -MODULE_AUTHOR("David Basden <davidb-linux@rcpt.to>"); -MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */ - -module_init(toim3232_sir_init); -module_exit(toim3232_sir_cleanup); diff --git a/drivers/staging/irda/drivers/via-ircc.c b/drivers/staging/irda/drivers/via-ircc.c deleted file mode 100644 index ca4442a9d631..000000000000 --- a/drivers/staging/irda/drivers/via-ircc.c +++ /dev/null @@ -1,1593 +0,0 @@ -/******************************************************************** - Filename: via-ircc.c - Version: 1.0 - Description: Driver for the VIA VT8231/VT8233 IrDA chipsets - Author: VIA Technologies,inc - Date : 08/06/2003 - -Copyright (c) 1998-2003 VIA Technologies, 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, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTIES OR REPRESENTATIONS; 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, see <http://www.gnu.org/licenses/>. - -F01 Oct/02/02: Modify code for V0.11(move out back to back transfer) -F02 Oct/28/02: Add SB device ID for 3147 and 3177. - Comment : - jul/09/2002 : only implement two kind of dongle currently. - Oct/02/2002 : work on VT8231 and VT8233 . - Aug/06/2003 : change driver format to pci driver . - -2004-02-16: <sda@bdit.de> -- Removed unneeded 'legacy' pci stuff. -- Make sure SIR mode is set (hw_init()) before calling mode-dependent stuff. -- On speed change from core, don't send SIR frame with new speed. - Use current speed and change speeds later. -- Make module-param dongle_id actually work. -- New dongle_id 17 (0x11): TDFS4500. Single-ended SIR only. - Tested with home-grown PCB on EPIA boards. -- Code cleanup. - - ********************************************************************/ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/rtnetlink.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/gfp.h> - -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/byteorder.h> - -#include <linux/pm.h> - -#include <net/irda/wrapper.h> -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#include "via-ircc.h" - -#define VIA_MODULE_NAME "via-ircc" -#define CHIP_IO_EXTENT 0x40 - -static char *driver_name = VIA_MODULE_NAME; - -/* Module parameters */ -static int qos_mtt_bits = 0x07; /* 1 ms or more */ -static int dongle_id = 0; /* default: probe */ - -/* We can't guess the type of connected dongle, user *must* supply it. */ -module_param(dongle_id, int, 0); - -/* Some prototypes */ -static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, - unsigned int id); -static int via_ircc_dma_receive(struct via_ircc_cb *self); -static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, - int iobase); -static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev); -static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev); -static void via_hw_init(struct via_ircc_cb *self); -static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud); -static irqreturn_t via_ircc_interrupt(int irq, void *dev_id); -static int via_ircc_is_receiving(struct via_ircc_cb *self); -static int via_ircc_read_dongle_id(int iobase); - -static int via_ircc_net_open(struct net_device *dev); -static int via_ircc_net_close(struct net_device *dev); -static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, - int cmd); -static void via_ircc_change_dongle_speed(int iobase, int speed, - int dongle_id); -static int RxTimerHandler(struct via_ircc_cb *self, int iobase); -static void hwreset(struct via_ircc_cb *self); -static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase); -static int upload_rxdata(struct via_ircc_cb *self, int iobase); -static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id); -static void via_remove_one(struct pci_dev *pdev); - -/* FIXME : Should use udelay() instead, even if we are x86 only - Jean II */ -static void iodelay(int udelay) -{ - u8 data; - int i; - - for (i = 0; i < udelay; i++) { - data = inb(0x80); - } -} - -static const struct pci_device_id via_pci_tbl[] = { - { PCI_VENDOR_ID_VIA, 0x8231, PCI_ANY_ID, PCI_ANY_ID,0,0,0 }, - { PCI_VENDOR_ID_VIA, 0x3109, PCI_ANY_ID, PCI_ANY_ID,0,0,1 }, - { PCI_VENDOR_ID_VIA, 0x3074, PCI_ANY_ID, PCI_ANY_ID,0,0,2 }, - { PCI_VENDOR_ID_VIA, 0x3147, PCI_ANY_ID, PCI_ANY_ID,0,0,3 }, - { PCI_VENDOR_ID_VIA, 0x3177, PCI_ANY_ID, PCI_ANY_ID,0,0,4 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci,via_pci_tbl); - - -static struct pci_driver via_driver = { - .name = VIA_MODULE_NAME, - .id_table = via_pci_tbl, - .probe = via_init_one, - .remove = via_remove_one, -}; - - -/* - * Function via_ircc_init () - * - * Initialize chip. Just find out chip type and resource. - */ -static int __init via_ircc_init(void) -{ - int rc; - - rc = pci_register_driver(&via_driver); - if (rc < 0) { - pr_debug("%s(): error rc = %d, returning -ENODEV...\n", - __func__, rc); - return -ENODEV; - } - return 0; -} - -static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) -{ - int rc; - u8 temp,oldPCI_40,oldPCI_44,bTmp,bTmp1; - u16 Chipset,FirDRQ1,FirDRQ0,FirIRQ,FirIOBase; - chipio_t info; - - pr_debug("%s(): Device ID=(0X%X)\n", __func__, id->device); - - rc = pci_enable_device (pcidev); - if (rc) { - pr_debug("%s(): error rc = %d\n", __func__, rc); - return -ENODEV; - } - - // South Bridge exist - if ( ReadLPCReg(0x20) != 0x3C ) - Chipset=0x3096; - else - Chipset=0x3076; - - if (Chipset==0x3076) { - pr_debug("%s(): Chipset = 3076\n", __func__); - - WriteLPCReg(7,0x0c ); - temp=ReadLPCReg(0x30);//check if BIOS Enable Fir - if((temp&0x01)==1) { // BIOS close or no FIR - WriteLPCReg(0x1d, 0x82 ); - WriteLPCReg(0x23,0x18); - temp=ReadLPCReg(0xF0); - if((temp&0x01)==0) { - temp=(ReadLPCReg(0x74)&0x03); //DMA - FirDRQ0=temp + 4; - temp=(ReadLPCReg(0x74)&0x0C) >> 2; - FirDRQ1=temp + 4; - } else { - temp=(ReadLPCReg(0x74)&0x0C) >> 2; //DMA - FirDRQ0=temp + 4; - FirDRQ1=FirDRQ0; - } - FirIRQ=(ReadLPCReg(0x70)&0x0f); //IRQ - FirIOBase=ReadLPCReg(0x60 ) << 8; //IO Space :high byte - FirIOBase=FirIOBase| ReadLPCReg(0x61) ; //low byte - FirIOBase=FirIOBase ; - info.fir_base=FirIOBase; - info.irq=FirIRQ; - info.dma=FirDRQ1; - info.dma2=FirDRQ0; - pci_read_config_byte(pcidev,0x40,&bTmp); - pci_write_config_byte(pcidev,0x40,((bTmp | 0x08) & 0xfe)); - pci_read_config_byte(pcidev,0x42,&bTmp); - pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0)); - pci_write_config_byte(pcidev,0x5a,0xc0); - WriteLPCReg(0x28, 0x70 ); - rc = via_ircc_open(pcidev, &info, 0x3076); - } else - rc = -ENODEV; //IR not turn on - } else { //Not VT1211 - pr_debug("%s(): Chipset = 3096\n", __func__); - - pci_read_config_byte(pcidev,0x67,&bTmp);//check if BIOS Enable Fir - if((bTmp&0x01)==1) { // BIOS enable FIR - //Enable Double DMA clock - pci_read_config_byte(pcidev,0x42,&oldPCI_40); - pci_write_config_byte(pcidev,0x42,oldPCI_40 | 0x80); - pci_read_config_byte(pcidev,0x40,&oldPCI_40); - pci_write_config_byte(pcidev,0x40,oldPCI_40 & 0xf7); - pci_read_config_byte(pcidev,0x44,&oldPCI_44); - pci_write_config_byte(pcidev,0x44,0x4e); - //---------- read configuration from Function0 of south bridge - if((bTmp&0x02)==0) { - pci_read_config_byte(pcidev,0x44,&bTmp1); //DMA - FirDRQ0 = (bTmp1 & 0x30) >> 4; - pci_read_config_byte(pcidev,0x44,&bTmp1); - FirDRQ1 = (bTmp1 & 0xc0) >> 6; - } else { - pci_read_config_byte(pcidev,0x44,&bTmp1); //DMA - FirDRQ0 = (bTmp1 & 0x30) >> 4 ; - FirDRQ1=0; - } - pci_read_config_byte(pcidev,0x47,&bTmp1); //IRQ - FirIRQ = bTmp1 & 0x0f; - - pci_read_config_byte(pcidev,0x69,&bTmp); - FirIOBase = bTmp << 8;//hight byte - pci_read_config_byte(pcidev,0x68,&bTmp); - FirIOBase = (FirIOBase | bTmp ) & 0xfff0; - //------------------------- - info.fir_base=FirIOBase; - info.irq=FirIRQ; - info.dma=FirDRQ1; - info.dma2=FirDRQ0; - rc = via_ircc_open(pcidev, &info, 0x3096); - } else - rc = -ENODEV; //IR not turn on !!!!! - }//Not VT1211 - - pr_debug("%s(): End - rc = %d\n", __func__, rc); - return rc; -} - -static void __exit via_ircc_cleanup(void) -{ - /* Cleanup all instances of the driver */ - pci_unregister_driver (&via_driver); -} - -static const struct net_device_ops via_ircc_sir_ops = { - .ndo_start_xmit = via_ircc_hard_xmit_sir, - .ndo_open = via_ircc_net_open, - .ndo_stop = via_ircc_net_close, - .ndo_do_ioctl = via_ircc_net_ioctl, -}; -static const struct net_device_ops via_ircc_fir_ops = { - .ndo_start_xmit = via_ircc_hard_xmit_fir, - .ndo_open = via_ircc_net_open, - .ndo_stop = via_ircc_net_close, - .ndo_do_ioctl = via_ircc_net_ioctl, -}; - -/* - * Function via_ircc_open(pdev, iobase, irq) - * - * Open driver instance - * - */ -static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, unsigned int id) -{ - struct net_device *dev; - struct via_ircc_cb *self; - int err; - - /* Allocate new instance of the driver */ - dev = alloc_irdadev(sizeof(struct via_ircc_cb)); - if (dev == NULL) - return -ENOMEM; - - self = netdev_priv(dev); - self->netdev = dev; - spin_lock_init(&self->lock); - - pci_set_drvdata(pdev, self); - - /* Initialize Resource */ - self->io.cfg_base = info->cfg_base; - self->io.fir_base = info->fir_base; - self->io.irq = info->irq; - self->io.fir_ext = CHIP_IO_EXTENT; - self->io.dma = info->dma; - self->io.dma2 = info->dma2; - self->io.fifo_size = 32; - self->chip_id = id; - self->st_fifo.len = 0; - self->RxDataReady = 0; - - /* Reserve the ioports that we need */ - if (!request_region(self->io.fir_base, self->io.fir_ext, driver_name)) { - pr_debug("%s(), can't get iobase of 0x%03x\n", - __func__, self->io.fir_base); - err = -ENODEV; - goto err_out1; - } - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - /* Check if user has supplied the dongle id or not */ - if (!dongle_id) - dongle_id = via_ircc_read_dongle_id(self->io.fir_base); - self->io.dongle_id = dongle_id; - - /* The only value we must override it the baudrate */ - /* Maximum speeds and capabilities are dongle-dependent. */ - switch( self->io.dongle_id ){ - case 0x0d: - self->qos.baud_rate.bits = - IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 | - IR_576000 | IR_1152000 | (IR_4000000 << 8); - break; - default: - self->qos.baud_rate.bits = - IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200; - break; - } - - /* Following was used for testing: - * - * self->qos.baud_rate.bits = IR_9600; - * - * Is is no good, as it prohibits (error-prone) speed-changes. - */ - - self->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&self->qos); - - /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ - self->rx_buff.truesize = 14384 + 2048; - self->tx_buff.truesize = 14384 + 2048; - - /* Allocate memory if needed */ - self->rx_buff.head = - dma_zalloc_coherent(&pdev->dev, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL); - if (self->rx_buff.head == NULL) { - err = -ENOMEM; - goto err_out2; - } - - self->tx_buff.head = - dma_zalloc_coherent(&pdev->dev, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL); - if (self->tx_buff.head == NULL) { - err = -ENOMEM; - goto err_out3; - } - - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - - /* Reset Tx queue info */ - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - - /* Override the network functions we need to use */ - dev->netdev_ops = &via_ircc_sir_ops; - - err = register_netdev(dev); - if (err) - goto err_out4; - - net_info_ratelimited("IrDA: Registered device %s (via-ircc)\n", - dev->name); - - /* Initialise the hardware.. - */ - self->io.speed = 9600; - via_hw_init(self); - return 0; - err_out4: - dma_free_coherent(&pdev->dev, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - err_out3: - dma_free_coherent(&pdev->dev, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - err_out2: - release_region(self->io.fir_base, self->io.fir_ext); - err_out1: - free_netdev(dev); - return err; -} - -/* - * Function via_remove_one(pdev) - * - * Close driver instance - * - */ -static void via_remove_one(struct pci_dev *pdev) -{ - struct via_ircc_cb *self = pci_get_drvdata(pdev); - int iobase; - - iobase = self->io.fir_base; - - ResetChip(iobase, 5); //hardware reset. - /* Remove netdevice */ - unregister_netdev(self->netdev); - - /* Release the PORT that this driver is using */ - pr_debug("%s(), Releasing Region %03x\n", - __func__, self->io.fir_base); - release_region(self->io.fir_base, self->io.fir_ext); - if (self->tx_buff.head) - dma_free_coherent(&pdev->dev, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - if (self->rx_buff.head) - dma_free_coherent(&pdev->dev, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - - free_netdev(self->netdev); - - pci_disable_device(pdev); -} - -/* - * Function via_hw_init(self) - * - * Returns non-negative on success. - * - * Formerly via_ircc_setup - */ -static void via_hw_init(struct via_ircc_cb *self) -{ - int iobase = self->io.fir_base; - - SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095 - // FIFO Init - EnRXFIFOReadyInt(iobase, OFF); - EnRXFIFOHalfLevelInt(iobase, OFF); - EnTXFIFOHalfLevelInt(iobase, OFF); - EnTXFIFOUnderrunEOMInt(iobase, ON); - EnTXFIFOReadyInt(iobase, OFF); - InvertTX(iobase, OFF); - InvertRX(iobase, OFF); - - if (ReadLPCReg(0x20) == 0x3c) - WriteLPCReg(0xF0, 0); // for VT1211 - /* Int Init */ - EnRXSpecInt(iobase, ON); - - /* The following is basically hwreset */ - /* If this is the case, why not just call hwreset() ? Jean II */ - ResetChip(iobase, 5); - EnableDMA(iobase, OFF); - EnableTX(iobase, OFF); - EnableRX(iobase, OFF); - EnRXDMA(iobase, OFF); - EnTXDMA(iobase, OFF); - RXStart(iobase, OFF); - TXStart(iobase, OFF); - InitCard(iobase); - CommonInit(iobase); - SIRFilter(iobase, ON); - SetSIR(iobase, ON); - CRC16(iobase, ON); - EnTXCRC(iobase, 0); - WriteReg(iobase, I_ST_CT_0, 0x00); - SetBaudRate(iobase, 9600); - SetPulseWidth(iobase, 12); - SetSendPreambleCount(iobase, 0); - - self->io.speed = 9600; - self->st_fifo.len = 0; - - via_ircc_change_dongle_speed(iobase, self->io.speed, - self->io.dongle_id); - - WriteReg(iobase, I_ST_CT_0, 0x80); -} - -/* - * Function via_ircc_read_dongle_id (void) - * - */ -static int via_ircc_read_dongle_id(int iobase) -{ - net_err_ratelimited("via-ircc: dongle probing not supported, please specify dongle_id module parameter\n"); - return 9; /* Default to IBM */ -} - -/* - * Function via_ircc_change_dongle_speed (iobase, speed, dongle_id) - * Change speed of the attach dongle - * only implement two type of dongle currently. - */ -static void via_ircc_change_dongle_speed(int iobase, int speed, - int dongle_id) -{ - u8 mode = 0; - - /* speed is unused, as we use IsSIROn()/IsMIROn() */ - speed = speed; - - pr_debug("%s(): change_dongle_speed to %d for 0x%x, %d\n", - __func__, speed, iobase, dongle_id); - - switch (dongle_id) { - - /* Note: The dongle_id's listed here are derived from - * nsc-ircc.c */ - - case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */ - UseOneRX(iobase, ON); // use one RX pin RX1,RX2 - InvertTX(iobase, OFF); - InvertRX(iobase, OFF); - - EnRX2(iobase, ON); //sir to rx2 - EnGPIOtoRX2(iobase, OFF); - - if (IsSIROn(iobase)) { //sir - // Mode select Off - SlowIRRXLowActive(iobase, ON); - udelay(1000); - SlowIRRXLowActive(iobase, OFF); - } else { - if (IsMIROn(iobase)) { //mir - // Mode select On - SlowIRRXLowActive(iobase, OFF); - udelay(20); - } else { // fir - if (IsFIROn(iobase)) { //fir - // Mode select On - SlowIRRXLowActive(iobase, OFF); - udelay(20); - } - } - } - break; - - case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */ - UseOneRX(iobase, ON); //use ONE RX....RX1 - InvertTX(iobase, OFF); - InvertRX(iobase, OFF); // invert RX pin - - EnRX2(iobase, ON); - EnGPIOtoRX2(iobase, OFF); - if (IsSIROn(iobase)) { //sir - // Mode select On - SlowIRRXLowActive(iobase, ON); - udelay(20); - // Mode select Off - SlowIRRXLowActive(iobase, OFF); - } - if (IsMIROn(iobase)) { //mir - // Mode select On - SlowIRRXLowActive(iobase, OFF); - udelay(20); - // Mode select Off - SlowIRRXLowActive(iobase, ON); - } else { // fir - if (IsFIROn(iobase)) { //fir - // Mode select On - SlowIRRXLowActive(iobase, OFF); - // TX On - WriteTX(iobase, ON); - udelay(20); - // Mode select OFF - SlowIRRXLowActive(iobase, ON); - udelay(20); - // TX Off - WriteTX(iobase, OFF); - } - } - break; - - case 0x0d: - UseOneRX(iobase, OFF); // use two RX pin RX1,RX2 - InvertTX(iobase, OFF); - InvertRX(iobase, OFF); - SlowIRRXLowActive(iobase, OFF); - if (IsSIROn(iobase)) { //sir - EnGPIOtoRX2(iobase, OFF); - WriteGIO(iobase, OFF); - EnRX2(iobase, OFF); //sir to rx2 - } else { // fir mir - EnGPIOtoRX2(iobase, OFF); - WriteGIO(iobase, OFF); - EnRX2(iobase, OFF); //fir to rx - } - break; - - case 0x11: /* Temic TFDS4500 */ - - pr_debug("%s: Temic TFDS4500: One RX pin, TX normal, RX inverted\n", - __func__); - - UseOneRX(iobase, ON); //use ONE RX....RX1 - InvertTX(iobase, OFF); - InvertRX(iobase, ON); // invert RX pin - - EnRX2(iobase, ON); //sir to rx2 - EnGPIOtoRX2(iobase, OFF); - - if( IsSIROn(iobase) ){ //sir - - // Mode select On - SlowIRRXLowActive(iobase, ON); - udelay(20); - // Mode select Off - SlowIRRXLowActive(iobase, OFF); - - } else{ - pr_debug("%s: Warning: TFDS4500 not running in SIR mode !\n", - __func__); - } - break; - - case 0x0ff: /* Vishay */ - if (IsSIROn(iobase)) - mode = 0; - else if (IsMIROn(iobase)) - mode = 1; - else if (IsFIROn(iobase)) - mode = 2; - else if (IsVFIROn(iobase)) - mode = 5; //VFIR-16 - SI_SetMode(iobase, mode); - break; - - default: - net_err_ratelimited("%s: Error: dongle_id %d unsupported !\n", - __func__, dongle_id); - } -} - -/* - * Function via_ircc_change_speed (self, baud) - * - * Change the speed of the device - * - */ -static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 speed) -{ - struct net_device *dev = self->netdev; - u16 iobase; - u8 value = 0, bTmp; - - iobase = self->io.fir_base; - /* Update accounting for new speed */ - self->io.speed = speed; - pr_debug("%s: change_speed to %d bps.\n", __func__, speed); - - WriteReg(iobase, I_ST_CT_0, 0x0); - - /* Controller mode sellection */ - switch (speed) { - case 2400: - case 9600: - case 19200: - case 38400: - case 57600: - case 115200: - value = (115200/speed)-1; - SetSIR(iobase, ON); - CRC16(iobase, ON); - break; - case 576000: - /* FIXME: this can't be right, as it's the same as 115200, - * and 576000 is MIR, not SIR. */ - value = 0; - SetSIR(iobase, ON); - CRC16(iobase, ON); - break; - case 1152000: - value = 0; - SetMIR(iobase, ON); - /* FIXME: CRC ??? */ - break; - case 4000000: - value = 0; - SetFIR(iobase, ON); - SetPulseWidth(iobase, 0); - SetSendPreambleCount(iobase, 14); - CRC16(iobase, OFF); - EnTXCRC(iobase, ON); - break; - case 16000000: - value = 0; - SetVFIR(iobase, ON); - /* FIXME: CRC ??? */ - break; - default: - value = 0; - break; - } - - /* Set baudrate to 0x19[2..7] */ - bTmp = (ReadReg(iobase, I_CF_H_1) & 0x03); - bTmp |= value << 2; - WriteReg(iobase, I_CF_H_1, bTmp); - - /* Some dongles may need to be informed about speed changes. */ - via_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id); - - /* Set FIFO size to 64 */ - SetFIFO(iobase, 64); - - /* Enable IR */ - WriteReg(iobase, I_ST_CT_0, 0x80); - - // EnTXFIFOHalfLevelInt(iobase,ON); - - /* Enable some interrupts so we can receive frames */ - //EnAllInt(iobase,ON); - - if (IsSIROn(iobase)) { - SIRFilter(iobase, ON); - SIRRecvAny(iobase, ON); - } else { - SIRFilter(iobase, OFF); - SIRRecvAny(iobase, OFF); - } - - if (speed > 115200) { - /* Install FIR xmit handler */ - dev->netdev_ops = &via_ircc_fir_ops; - via_ircc_dma_receive(self); - } else { - /* Install SIR xmit handler */ - dev->netdev_ops = &via_ircc_sir_ops; - } - netif_wake_queue(dev); -} - -/* - * Function via_ircc_hard_xmit (skb, dev) - * - * Transmit the frame! - * - */ -static netdev_tx_t via_ircc_hard_xmit_sir(struct sk_buff *skb, - struct net_device *dev) -{ - struct via_ircc_cb *self; - unsigned long flags; - u16 iobase; - __u32 speed; - - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;); - iobase = self->io.fir_base; - - netif_stop_queue(dev); - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - /* Check for empty frame */ - if (!skb->len) { - via_ircc_change_speed(self, speed); - netif_trans_update(dev); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else - self->new_speed = speed; - } - InitCard(iobase); - CommonInit(iobase); - SIRFilter(iobase, ON); - SetSIR(iobase, ON); - CRC16(iobase, ON); - EnTXCRC(iobase, 0); - WriteReg(iobase, I_ST_CT_0, 0x00); - - spin_lock_irqsave(&self->lock, flags); - self->tx_buff.data = self->tx_buff.head; - self->tx_buff.len = - async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - dev->stats.tx_bytes += self->tx_buff.len; - /* Send this frame with old speed */ - SetBaudRate(iobase, self->io.speed); - SetPulseWidth(iobase, 12); - SetSendPreambleCount(iobase, 0); - WriteReg(iobase, I_ST_CT_0, 0x80); - - EnableTX(iobase, ON); - EnableRX(iobase, OFF); - - ResetChip(iobase, 0); - ResetChip(iobase, 1); - ResetChip(iobase, 2); - ResetChip(iobase, 3); - ResetChip(iobase, 4); - - EnAllInt(iobase, ON); - EnTXDMA(iobase, ON); - EnRXDMA(iobase, OFF); - - irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, - DMA_TX_MODE); - - SetSendByte(iobase, self->tx_buff.len); - RXStart(iobase, OFF); - TXStart(iobase, ON); - - netif_trans_update(dev); - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - -static netdev_tx_t via_ircc_hard_xmit_fir(struct sk_buff *skb, - struct net_device *dev) -{ - struct via_ircc_cb *self; - u16 iobase; - __u32 speed; - unsigned long flags; - - self = netdev_priv(dev); - iobase = self->io.fir_base; - - if (self->st_fifo.len) - return NETDEV_TX_OK; - if (self->chip_id == 0x3076) - iodelay(1500); - else - udelay(1500); - netif_stop_queue(dev); - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - if (!skb->len) { - via_ircc_change_speed(self, speed); - netif_trans_update(dev); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else - self->new_speed = speed; - } - spin_lock_irqsave(&self->lock, flags); - self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail; - self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; - - self->tx_fifo.tail += skb->len; - dev->stats.tx_bytes += skb->len; - skb_copy_from_linear_data(skb, - self->tx_fifo.queue[self->tx_fifo.free].start, skb->len); - self->tx_fifo.len++; - self->tx_fifo.free++; -//F01 if (self->tx_fifo.len == 1) { - via_ircc_dma_xmit(self, iobase); -//F01 } -//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) netif_wake_queue(self->netdev); - netif_trans_update(dev); - dev_kfree_skb(skb); - spin_unlock_irqrestore(&self->lock, flags); - return NETDEV_TX_OK; - -} - -static int via_ircc_dma_xmit(struct via_ircc_cb *self, u16 iobase) -{ - EnTXDMA(iobase, OFF); - self->io.direction = IO_XMIT; - EnPhys(iobase, ON); - EnableTX(iobase, ON); - EnableRX(iobase, OFF); - ResetChip(iobase, 0); - ResetChip(iobase, 1); - ResetChip(iobase, 2); - ResetChip(iobase, 3); - ResetChip(iobase, 4); - EnAllInt(iobase, ON); - EnTXDMA(iobase, ON); - EnRXDMA(iobase, OFF); - irda_setup_dma(self->io.dma, - ((u8 *)self->tx_fifo.queue[self->tx_fifo.ptr].start - - self->tx_buff.head) + self->tx_buff_dma, - self->tx_fifo.queue[self->tx_fifo.ptr].len, DMA_TX_MODE); - pr_debug("%s: tx_fifo.ptr=%x,len=%x,tx_fifo.len=%x..\n", - __func__, self->tx_fifo.ptr, - self->tx_fifo.queue[self->tx_fifo.ptr].len, - self->tx_fifo.len); - - SetSendByte(iobase, self->tx_fifo.queue[self->tx_fifo.ptr].len); - RXStart(iobase, OFF); - TXStart(iobase, ON); - return 0; - -} - -/* - * Function via_ircc_dma_xmit_complete (self) - * - * The transfer of a frame in finished. This function will only be called - * by the interrupt handler - * - */ -static int via_ircc_dma_xmit_complete(struct via_ircc_cb *self) -{ - int iobase; - u8 Tx_status; - - iobase = self->io.fir_base; - /* Disable DMA */ -// DisableDmaChannel(self->io.dma); - /* Check for underrun! */ - /* Clear bit, by writing 1 into it */ - Tx_status = GetTXStatus(iobase); - if (Tx_status & 0x08) { - self->netdev->stats.tx_errors++; - self->netdev->stats.tx_fifo_errors++; - hwreset(self); - /* how to clear underrun? */ - } else { - self->netdev->stats.tx_packets++; - ResetChip(iobase, 3); - ResetChip(iobase, 4); - } - /* Check if we need to change the speed */ - if (self->new_speed) { - via_ircc_change_speed(self, self->new_speed); - self->new_speed = 0; - } - - /* Finished with this frame, so prepare for next */ - if (IsFIROn(iobase)) { - if (self->tx_fifo.len) { - self->tx_fifo.len--; - self->tx_fifo.ptr++; - } - } - pr_debug("%s: tx_fifo.len=%x ,tx_fifo.ptr=%x,tx_fifo.free=%x...\n", - __func__, - self->tx_fifo.len, self->tx_fifo.ptr, self->tx_fifo.free); -/* F01_S - // Any frames to be sent back-to-back? - if (self->tx_fifo.len) { - // Not finished yet! - via_ircc_dma_xmit(self, iobase); - ret = FALSE; - } else { -F01_E*/ - // Reset Tx FIFO info - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; -//F01 } - - // Make sure we have room for more frames -//F01 if (self->tx_fifo.free < (MAX_TX_WINDOW -1 )) { - // Not busy transmitting anymore - // Tell the network layer, that we can accept more frames - netif_wake_queue(self->netdev); -//F01 } - return TRUE; -} - -/* - * Function via_ircc_dma_receive (self) - * - * Set configuration for receive a frame. - * - */ -static int via_ircc_dma_receive(struct via_ircc_cb *self) -{ - int iobase; - - iobase = self->io.fir_base; - - self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0; - self->tx_fifo.tail = self->tx_buff.head; - self->RxDataReady = 0; - self->io.direction = IO_RECV; - self->rx_buff.data = self->rx_buff.head; - self->st_fifo.len = self->st_fifo.pending_bytes = 0; - self->st_fifo.tail = self->st_fifo.head = 0; - - EnPhys(iobase, ON); - EnableTX(iobase, OFF); - EnableRX(iobase, ON); - - ResetChip(iobase, 0); - ResetChip(iobase, 1); - ResetChip(iobase, 2); - ResetChip(iobase, 3); - ResetChip(iobase, 4); - - EnAllInt(iobase, ON); - EnTXDMA(iobase, OFF); - EnRXDMA(iobase, ON); - irda_setup_dma(self->io.dma2, self->rx_buff_dma, - self->rx_buff.truesize, DMA_RX_MODE); - TXStart(iobase, OFF); - RXStart(iobase, ON); - - return 0; -} - -/* - * Function via_ircc_dma_receive_complete (self) - * - * Controller Finished with receiving frames, - * and this routine is call by ISR - * - */ -static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, - int iobase) -{ - struct st_fifo *st_fifo; - struct sk_buff *skb; - int len, i; - u8 status = 0; - - iobase = self->io.fir_base; - st_fifo = &self->st_fifo; - - if (self->io.speed < 4000000) { //Speed below FIR - len = GetRecvByte(iobase, self); - skb = dev_alloc_skb(len + 1); - if (skb == NULL) - return FALSE; - // Make sure IP header gets aligned - skb_reserve(skb, 1); - skb_put(skb, len - 2); - if (self->chip_id == 0x3076) { - for (i = 0; i < len - 2; i++) - skb->data[i] = self->rx_buff.data[i * 2]; - } else { - if (self->chip_id == 0x3096) { - for (i = 0; i < len - 2; i++) - skb->data[i] = - self->rx_buff.data[i]; - } - } - // Move to next frame - self->rx_buff.data += len; - self->netdev->stats.rx_bytes += len; - self->netdev->stats.rx_packets++; - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - return TRUE; - } - - else { //FIR mode - len = GetRecvByte(iobase, self); - if (len == 0) - return TRUE; //interrupt only, data maybe move by RxT - if (((len - 4) < 2) || ((len - 4) > 2048)) { - pr_debug("%s(): Trouble:len=%x,CurCount=%x,LastCount=%x\n", - __func__, len, RxCurCount(iobase, self), - self->RxLastCount); - hwreset(self); - return FALSE; - } - pr_debug("%s(): fifo.len=%x,len=%x,CurCount=%x..\n", - __func__, - st_fifo->len, len - 4, RxCurCount(iobase, self)); - - st_fifo->entries[st_fifo->tail].status = status; - st_fifo->entries[st_fifo->tail].len = len; - st_fifo->pending_bytes += len; - st_fifo->tail++; - st_fifo->len++; - if (st_fifo->tail > MAX_RX_WINDOW) - st_fifo->tail = 0; - self->RxDataReady = 0; - - // It maybe have MAX_RX_WINDOW package receive by - // receive_complete before Timer IRQ -/* F01_S - if (st_fifo->len < (MAX_RX_WINDOW+2 )) { - RXStart(iobase,ON); - SetTimer(iobase,4); - } - else { -F01_E */ - EnableRX(iobase, OFF); - EnRXDMA(iobase, OFF); - RXStart(iobase, OFF); -//F01_S - // Put this entry back in fifo - if (st_fifo->head > MAX_RX_WINDOW) - st_fifo->head = 0; - status = st_fifo->entries[st_fifo->head].status; - len = st_fifo->entries[st_fifo->head].len; - st_fifo->head++; - st_fifo->len--; - - skb = dev_alloc_skb(len + 1 - 4); - /* - * if frame size, data ptr, or skb ptr are wrong, then get next - * entry. - */ - if ((skb == NULL) || (skb->data == NULL) || - (self->rx_buff.data == NULL) || (len < 6)) { - self->netdev->stats.rx_dropped++; - kfree_skb(skb); - return TRUE; - } - skb_reserve(skb, 1); - skb_put(skb, len - 4); - - skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); - pr_debug("%s(): len=%x.rx_buff=%p\n", __func__, - len - 4, self->rx_buff.data); - - // Move to next frame - self->rx_buff.data += len; - self->netdev->stats.rx_bytes += len; - self->netdev->stats.rx_packets++; - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - -//F01_E - } //FIR - return TRUE; - -} - -/* - * if frame is received , but no INT ,then use this routine to upload frame. - */ -static int upload_rxdata(struct via_ircc_cb *self, int iobase) -{ - struct sk_buff *skb; - int len; - struct st_fifo *st_fifo; - st_fifo = &self->st_fifo; - - len = GetRecvByte(iobase, self); - - pr_debug("%s(): len=%x\n", __func__, len); - - if ((len - 4) < 2) { - self->netdev->stats.rx_dropped++; - return FALSE; - } - - skb = dev_alloc_skb(len + 1); - if (skb == NULL) { - self->netdev->stats.rx_dropped++; - return FALSE; - } - skb_reserve(skb, 1); - skb_put(skb, len - 4 + 1); - skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4 + 1); - st_fifo->tail++; - st_fifo->len++; - if (st_fifo->tail > MAX_RX_WINDOW) - st_fifo->tail = 0; - // Move to next frame - self->rx_buff.data += len; - self->netdev->stats.rx_bytes += len; - self->netdev->stats.rx_packets++; - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - if (st_fifo->len < (MAX_RX_WINDOW + 2)) { - RXStart(iobase, ON); - } else { - EnableRX(iobase, OFF); - EnRXDMA(iobase, OFF); - RXStart(iobase, OFF); - } - return TRUE; -} - -/* - * Implement back to back receive , use this routine to upload data. - */ - -static int RxTimerHandler(struct via_ircc_cb *self, int iobase) -{ - struct st_fifo *st_fifo; - struct sk_buff *skb; - int len; - u8 status; - - st_fifo = &self->st_fifo; - - if (CkRxRecv(iobase, self)) { - // if still receiving ,then return ,don't upload frame - self->RetryCount = 0; - SetTimer(iobase, 20); - self->RxDataReady++; - return FALSE; - } else - self->RetryCount++; - - if ((self->RetryCount >= 1) || - ((st_fifo->pending_bytes + 2048) > self->rx_buff.truesize) || - (st_fifo->len >= (MAX_RX_WINDOW))) { - while (st_fifo->len > 0) { //upload frame - // Put this entry back in fifo - if (st_fifo->head > MAX_RX_WINDOW) - st_fifo->head = 0; - status = st_fifo->entries[st_fifo->head].status; - len = st_fifo->entries[st_fifo->head].len; - st_fifo->head++; - st_fifo->len--; - - skb = dev_alloc_skb(len + 1 - 4); - /* - * if frame size, data ptr, or skb ptr are wrong, - * then get next entry. - */ - if ((skb == NULL) || (skb->data == NULL) || - (self->rx_buff.data == NULL) || (len < 6)) { - self->netdev->stats.rx_dropped++; - continue; - } - skb_reserve(skb, 1); - skb_put(skb, len - 4); - skb_copy_to_linear_data(skb, self->rx_buff.data, len - 4); - - pr_debug("%s(): len=%x.head=%x\n", __func__, - len - 4, st_fifo->head); - - // Move to next frame - self->rx_buff.data += len; - self->netdev->stats.rx_bytes += len; - self->netdev->stats.rx_packets++; - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - } //while - self->RetryCount = 0; - - pr_debug("%s(): End of upload HostStatus=%x,RxStatus=%x\n", - __func__, GetHostStatus(iobase), GetRXStatus(iobase)); - - /* - * if frame is receive complete at this routine ,then upload - * frame. - */ - if ((GetRXStatus(iobase) & 0x10) && - (RxCurCount(iobase, self) != self->RxLastCount)) { - upload_rxdata(self, iobase); - if (irda_device_txqueue_empty(self->netdev)) - via_ircc_dma_receive(self); - } - } // timer detect complete - else - SetTimer(iobase, 4); - return TRUE; - -} - - - -/* - * Function via_ircc_interrupt (irq, dev_id) - * - * An interrupt from the chip has arrived. Time to do some work - * - */ -static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) -{ - struct net_device *dev = dev_id; - struct via_ircc_cb *self = netdev_priv(dev); - int iobase; - u8 iHostIntType, iRxIntType, iTxIntType; - - iobase = self->io.fir_base; - spin_lock(&self->lock); - iHostIntType = GetHostStatus(iobase); - - pr_debug("%s(): iHostIntType %02x: %s %s %s %02x\n", - __func__, iHostIntType, - (iHostIntType & 0x40) ? "Timer" : "", - (iHostIntType & 0x20) ? "Tx" : "", - (iHostIntType & 0x10) ? "Rx" : "", - (iHostIntType & 0x0e) >> 1); - - if ((iHostIntType & 0x40) != 0) { //Timer Event - self->EventFlag.TimeOut++; - ClearTimerInt(iobase, 1); - if (self->io.direction == IO_XMIT) { - via_ircc_dma_xmit(self, iobase); - } - if (self->io.direction == IO_RECV) { - /* - * frame ready hold too long, must reset. - */ - if (self->RxDataReady > 30) { - hwreset(self); - if (irda_device_txqueue_empty(self->netdev)) { - via_ircc_dma_receive(self); - } - } else { // call this to upload frame. - RxTimerHandler(self, iobase); - } - } //RECV - } //Timer Event - if ((iHostIntType & 0x20) != 0) { //Tx Event - iTxIntType = GetTXStatus(iobase); - - pr_debug("%s(): iTxIntType %02x: %s %s %s %s\n", - __func__, iTxIntType, - (iTxIntType & 0x08) ? "FIFO underr." : "", - (iTxIntType & 0x04) ? "EOM" : "", - (iTxIntType & 0x02) ? "FIFO ready" : "", - (iTxIntType & 0x01) ? "Early EOM" : ""); - - if (iTxIntType & 0x4) { - self->EventFlag.EOMessage++; // read and will auto clean - if (via_ircc_dma_xmit_complete(self)) { - if (irda_device_txqueue_empty - (self->netdev)) { - via_ircc_dma_receive(self); - } - } else { - self->EventFlag.Unknown++; - } - } //EOP - } //Tx Event - //---------------------------------------- - if ((iHostIntType & 0x10) != 0) { //Rx Event - /* Check if DMA has finished */ - iRxIntType = GetRXStatus(iobase); - - pr_debug("%s(): iRxIntType %02x: %s %s %s %s %s %s %s\n", - __func__, iRxIntType, - (iRxIntType & 0x80) ? "PHY err." : "", - (iRxIntType & 0x40) ? "CRC err" : "", - (iRxIntType & 0x20) ? "FIFO overr." : "", - (iRxIntType & 0x10) ? "EOF" : "", - (iRxIntType & 0x08) ? "RxData" : "", - (iRxIntType & 0x02) ? "RxMaxLen" : "", - (iRxIntType & 0x01) ? "SIR bad" : ""); - if (!iRxIntType) - pr_debug("%s(): RxIRQ =0\n", __func__); - - if (iRxIntType & 0x10) { - if (via_ircc_dma_receive_complete(self, iobase)) { -//F01 if(!(IsFIROn(iobase))) via_ircc_dma_receive(self); - via_ircc_dma_receive(self); - } - } // No ERR - else { //ERR - pr_debug("%s(): RxIRQ ERR:iRxIntType=%x,HostIntType=%x,CurCount=%x,RxLastCount=%x_____\n", - __func__, iRxIntType, iHostIntType, - RxCurCount(iobase, self), self->RxLastCount); - - if (iRxIntType & 0x20) { //FIFO OverRun ERR - ResetChip(iobase, 0); - ResetChip(iobase, 1); - } else { //PHY,CRC ERR - - if (iRxIntType != 0x08) - hwreset(self); //F01 - } - via_ircc_dma_receive(self); - } //ERR - - } //Rx Event - spin_unlock(&self->lock); - return IRQ_RETVAL(iHostIntType); -} - -static void hwreset(struct via_ircc_cb *self) -{ - int iobase; - iobase = self->io.fir_base; - - ResetChip(iobase, 5); - EnableDMA(iobase, OFF); - EnableTX(iobase, OFF); - EnableRX(iobase, OFF); - EnRXDMA(iobase, OFF); - EnTXDMA(iobase, OFF); - RXStart(iobase, OFF); - TXStart(iobase, OFF); - InitCard(iobase); - CommonInit(iobase); - SIRFilter(iobase, ON); - SetSIR(iobase, ON); - CRC16(iobase, ON); - EnTXCRC(iobase, 0); - WriteReg(iobase, I_ST_CT_0, 0x00); - SetBaudRate(iobase, 9600); - SetPulseWidth(iobase, 12); - SetSendPreambleCount(iobase, 0); - WriteReg(iobase, I_ST_CT_0, 0x80); - - /* Restore speed. */ - via_ircc_change_speed(self, self->io.speed); - - self->st_fifo.len = 0; -} - -/* - * Function via_ircc_is_receiving (self) - * - * Return TRUE is we are currently receiving a frame - * - */ -static int via_ircc_is_receiving(struct via_ircc_cb *self) -{ - int status = FALSE; - int iobase; - - IRDA_ASSERT(self != NULL, return FALSE;); - - iobase = self->io.fir_base; - if (CkRxRecv(iobase, self)) - status = TRUE; - - pr_debug("%s(): status=%x....\n", __func__, status); - - return status; -} - - -/* - * Function via_ircc_net_open (dev) - * - * Start the device - * - */ -static int via_ircc_net_open(struct net_device *dev) -{ - struct via_ircc_cb *self; - int iobase; - char hwname[32]; - - IRDA_ASSERT(dev != NULL, return -1;); - self = netdev_priv(dev); - dev->stats.rx_packets = 0; - IRDA_ASSERT(self != NULL, return 0;); - iobase = self->io.fir_base; - if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) { - net_warn_ratelimited("%s, unable to allocate irq=%d\n", - driver_name, self->io.irq); - return -EAGAIN; - } - /* - * Always allocate the DMA channel after the IRQ, and clean up on - * failure. - */ - if (request_dma(self->io.dma, dev->name)) { - net_warn_ratelimited("%s, unable to allocate dma=%d\n", - driver_name, self->io.dma); - free_irq(self->io.irq, dev); - return -EAGAIN; - } - if (self->io.dma2 != self->io.dma) { - if (request_dma(self->io.dma2, dev->name)) { - net_warn_ratelimited("%s, unable to allocate dma2=%d\n", - driver_name, self->io.dma2); - free_irq(self->io.irq, dev); - free_dma(self->io.dma); - return -EAGAIN; - } - } - - - /* turn on interrupts */ - EnAllInt(iobase, ON); - EnInternalLoop(iobase, OFF); - EnExternalLoop(iobase, OFF); - - /* */ - via_ircc_dma_receive(self); - - /* Ready to play! */ - netif_start_queue(dev); - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - sprintf(hwname, "VIA @ 0x%x", iobase); - self->irlap = irlap_open(dev, &self->qos, hwname); - - self->RxLastCount = 0; - - return 0; -} - -/* - * Function via_ircc_net_close (dev) - * - * Stop the device - * - */ -static int via_ircc_net_close(struct net_device *dev) -{ - struct via_ircc_cb *self; - int iobase; - - IRDA_ASSERT(dev != NULL, return -1;); - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return 0;); - - /* Stop device */ - netif_stop_queue(dev); - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - iobase = self->io.fir_base; - EnTXDMA(iobase, OFF); - EnRXDMA(iobase, OFF); - DisableDmaChannel(self->io.dma); - - /* Disable interrupts */ - EnAllInt(iobase, OFF); - free_irq(self->io.irq, dev); - free_dma(self->io.dma); - if (self->io.dma2 != self->io.dma) - free_dma(self->io.dma2); - - return 0; -} - -/* - * Function via_ircc_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, - int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct via_ircc_cb *self; - unsigned long flags; - int ret = 0; - - IRDA_ASSERT(dev != NULL, return -1;); - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return -1;); - pr_debug("%s(), %s, (cmd=0x%X)\n", __func__, dev->name, - cmd); - /* Disable interrupts & save flags */ - spin_lock_irqsave(&self->lock, flags); - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto out; - } - via_ircc_change_speed(self, irq->ifr_baudrate); - break; - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto out; - } - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = via_ircc_is_receiving(self); - break; - default: - ret = -EOPNOTSUPP; - } - out: - spin_unlock_irqrestore(&self->lock, flags); - return ret; -} - -MODULE_AUTHOR("VIA Technologies,inc"); -MODULE_DESCRIPTION("VIA IrDA Device Driver"); -MODULE_LICENSE("GPL"); - -module_init(via_ircc_init); -module_exit(via_ircc_cleanup); diff --git a/drivers/staging/irda/drivers/via-ircc.h b/drivers/staging/irda/drivers/via-ircc.h deleted file mode 100644 index ac1525573398..000000000000 --- a/drivers/staging/irda/drivers/via-ircc.h +++ /dev/null @@ -1,846 +0,0 @@ -/********************************************************************* - * - * Filename: via-ircc.h - * Version: 1.0 - * Description: Driver for the VIA VT8231/VT8233 IrDA chipsets - * Author: VIA Technologies, inc - * Date : 08/06/2003 - -Copyright (c) 1998-2003 VIA Technologies, 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, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTIES OR REPRESENTATIONS; 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, see <http://www.gnu.org/licenses/>. - - * Comment: - * jul/08/2002 : Rx buffer length should use Rx ring ptr. - * Oct/28/2002 : Add SB id for 3147 and 3177. - * jul/09/2002 : only implement two kind of dongle currently. - * Oct/02/2002 : work on VT8231 and VT8233 . - * Aug/06/2003 : change driver format to pci driver . - ********************************************************************/ -#ifndef via_IRCC_H -#define via_IRCC_H -#include <linux/spinlock.h> -#include <linux/pm.h> -#include <linux/types.h> -#include <asm/io.h> - -#define MAX_TX_WINDOW 7 -#define MAX_RX_WINDOW 7 - -struct st_fifo_entry { - int status; - int len; -}; - -struct st_fifo { - struct st_fifo_entry entries[MAX_RX_WINDOW + 2]; - int pending_bytes; - int head; - int tail; - int len; -}; - -struct frame_cb { - void *start; /* Start of frame in DMA mem */ - int len; /* Length of frame in DMA mem */ -}; - -struct tx_fifo { - struct frame_cb queue[MAX_TX_WINDOW + 2]; /* Info about frames in queue */ - int ptr; /* Currently being sent */ - int len; /* Length of queue */ - int free; /* Next free slot */ - void *tail; /* Next free start in DMA mem */ -}; - - -struct eventflag // for keeping track of Interrupt Events -{ - //--------tx part - unsigned char TxFIFOUnderRun; - unsigned char EOMessage; - unsigned char TxFIFOReady; - unsigned char EarlyEOM; - //--------rx part - unsigned char PHYErr; - unsigned char CRCErr; - unsigned char RxFIFOOverRun; - unsigned char EOPacket; - unsigned char RxAvail; - unsigned char TooLargePacket; - unsigned char SIRBad; - //--------unknown - unsigned char Unknown; - //---------- - unsigned char TimeOut; - unsigned char RxDMATC; - unsigned char TxDMATC; -}; - -/* Private data for each instance */ -struct via_ircc_cb { - struct st_fifo st_fifo; /* Info about received frames */ - struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ - - struct net_device *netdev; /* Yes! we are some kind of netdevice */ - - struct irlap_cb *irlap; /* The link layer we are binded to */ - struct qos_info qos; /* QoS capabilities for this device */ - - chipio_t io; /* IrDA controller information */ - iobuff_t tx_buff; /* Transmit buffer */ - iobuff_t rx_buff; /* Receive buffer */ - dma_addr_t tx_buff_dma; - dma_addr_t rx_buff_dma; - - __u8 ier; /* Interrupt enable register */ - - spinlock_t lock; /* For serializing operations */ - - __u32 flags; /* Interface flags */ - __u32 new_speed; - int index; /* Instance index */ - - struct eventflag EventFlag; - unsigned int chip_id; /* to remember chip id */ - unsigned int RetryCount; - unsigned int RxDataReady; - unsigned int RxLastCount; -}; - - -//---------I=Infrared, H=Host, M=Misc, T=Tx, R=Rx, ST=Status, -// CF=Config, CT=Control, L=Low, H=High, C=Count -#define I_CF_L_0 0x10 -#define I_CF_H_0 0x11 -#define I_SIR_BOF 0x12 -#define I_SIR_EOF 0x13 -#define I_ST_CT_0 0x15 -#define I_ST_L_1 0x16 -#define I_ST_H_1 0x17 -#define I_CF_L_1 0x18 -#define I_CF_H_1 0x19 -#define I_CF_L_2 0x1a -#define I_CF_H_2 0x1b -#define I_CF_3 0x1e -#define H_CT 0x20 -#define H_ST 0x21 -#define M_CT 0x22 -#define TX_CT_1 0x23 -#define TX_CT_2 0x24 -#define TX_ST 0x25 -#define RX_CT 0x26 -#define RX_ST 0x27 -#define RESET 0x28 -#define P_ADDR 0x29 -#define RX_C_L 0x2a -#define RX_C_H 0x2b -#define RX_P_L 0x2c -#define RX_P_H 0x2d -#define TX_C_L 0x2e -#define TX_C_H 0x2f -#define TIMER 0x32 -#define I_CF_4 0x33 -#define I_T_C_L 0x34 -#define I_T_C_H 0x35 -#define VERSION 0x3f -//------------------------------- -#define StartAddr 0x10 // the first register address -#define EndAddr 0x3f // the last register address -#define GetBit(val,bit) val = (unsigned char) ((val>>bit) & 0x1) - // Returns the bit -#define SetBit(val,bit) val= (unsigned char ) (val | (0x1 << bit)) - // Sets bit to 1 -#define ResetBit(val,bit) val= (unsigned char ) (val & ~(0x1 << bit)) - // Sets bit to 0 - -#define OFF 0 -#define ON 1 -#define DMA_TX_MODE 0x08 -#define DMA_RX_MODE 0x04 - -#define DMA1 0 -#define DMA2 0xc0 -#define MASK1 DMA1+0x0a -#define MASK2 DMA2+0x14 - -#define Clk_bit 0x40 -#define Tx_bit 0x01 -#define Rd_Valid 0x08 -#define RxBit 0x08 - -static void DisableDmaChannel(unsigned int channel) -{ - switch (channel) { // 8 Bit DMA channels DMAC1 - case 0: - outb(4, MASK1); //mask channel 0 - break; - case 1: - outb(5, MASK1); //Mask channel 1 - break; - case 2: - outb(6, MASK1); //Mask channel 2 - break; - case 3: - outb(7, MASK1); //Mask channel 3 - break; - case 5: - outb(5, MASK2); //Mask channel 5 - break; - case 6: - outb(6, MASK2); //Mask channel 6 - break; - case 7: - outb(7, MASK2); //Mask channel 7 - break; - default: - break; - } -} - -static unsigned char ReadLPCReg(int iRegNum) -{ - unsigned char iVal; - - outb(0x87, 0x2e); - outb(0x87, 0x2e); - outb(iRegNum, 0x2e); - iVal = inb(0x2f); - outb(0xaa, 0x2e); - - return iVal; -} - -static void WriteLPCReg(int iRegNum, unsigned char iVal) -{ - - outb(0x87, 0x2e); - outb(0x87, 0x2e); - outb(iRegNum, 0x2e); - outb(iVal, 0x2f); - outb(0xAA, 0x2e); -} - -static __u8 ReadReg(unsigned int BaseAddr, int iRegNum) -{ - return (__u8) inb(BaseAddr + iRegNum); -} - -static void WriteReg(unsigned int BaseAddr, int iRegNum, unsigned char iVal) -{ - outb(iVal, BaseAddr + iRegNum); -} - -static int WriteRegBit(unsigned int BaseAddr, unsigned char RegNum, - unsigned char BitPos, unsigned char value) -{ - __u8 Rtemp, Wtemp; - - if (BitPos > 7) { - return -1; - } - if ((RegNum < StartAddr) || (RegNum > EndAddr)) - return -1; - Rtemp = ReadReg(BaseAddr, RegNum); - if (value == 0) - Wtemp = ResetBit(Rtemp, BitPos); - else { - if (value == 1) - Wtemp = SetBit(Rtemp, BitPos); - else - return -1; - } - WriteReg(BaseAddr, RegNum, Wtemp); - return 0; -} - -static __u8 CheckRegBit(unsigned int BaseAddr, unsigned char RegNum, - unsigned char BitPos) -{ - __u8 temp; - - if (BitPos > 7) - return 0xff; - if ((RegNum < StartAddr) || (RegNum > EndAddr)) { -// printf("what is the register %x!\n",RegNum); - } - temp = ReadReg(BaseAddr, RegNum); - return GetBit(temp, BitPos); -} - -static void SetMaxRxPacketSize(__u16 iobase, __u16 size) -{ - __u16 low, high; - if ((size & 0xe000) == 0) { - low = size & 0x00ff; - high = (size & 0x1f00) >> 8; - WriteReg(iobase, I_CF_L_2, low); - WriteReg(iobase, I_CF_H_2, high); - - } - -} - -//for both Rx and Tx - -static void SetFIFO(__u16 iobase, __u16 value) -{ - switch (value) { - case 128: - WriteRegBit(iobase, 0x11, 0, 0); - WriteRegBit(iobase, 0x11, 7, 1); - break; - case 64: - WriteRegBit(iobase, 0x11, 0, 0); - WriteRegBit(iobase, 0x11, 7, 0); - break; - case 32: - WriteRegBit(iobase, 0x11, 0, 1); - WriteRegBit(iobase, 0x11, 7, 0); - break; - default: - WriteRegBit(iobase, 0x11, 0, 0); - WriteRegBit(iobase, 0x11, 7, 0); - } - -} - -#define CRC16(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,7,val) //0 for 32 CRC -/* -#define SetVFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,5,val) -#define SetFIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,6,val) -#define SetMIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,5,val) -#define SetSIR(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,4,val) -*/ -#define SIRFilter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,3,val) -#define Filter(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,2,val) -#define InvertTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,1,val) -#define InvertRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_L_0,0,val) -//****************************I_CF_H_0 -#define EnableTX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,4,val) -#define EnableRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,3,val) -#define EnableDMA(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,2,val) -#define SIRRecvAny(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,1,val) -#define DiableTrans(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_H_0,0,val) -//***************************I_SIR_BOF,I_SIR_EOF -#define SetSIRBOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_BOF,val) -#define SetSIREOF(BaseAddr,val) WriteReg(BaseAddr,I_SIR_EOF,val) -#define GetSIRBOF(BaseAddr) ReadReg(BaseAddr,I_SIR_BOF) -#define GetSIREOF(BaseAddr) ReadReg(BaseAddr,I_SIR_EOF) -//*******************I_ST_CT_0 -#define EnPhys(BaseAddr,val) WriteRegBit(BaseAddr,I_ST_CT_0,7,val) -#define IsModeError(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,6) //RO -#define IsVFIROn(BaseAddr) CheckRegBit(BaseAddr,0x14,0) //RO for VT1211 only -#define IsFIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,5) //RO -#define IsMIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,4) //RO -#define IsSIROn(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,3) //RO -#define IsEnableTX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,2) //RO -#define IsEnableRX(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,1) //RO -#define Is16CRC(BaseAddr) CheckRegBit(BaseAddr,I_ST_CT_0,0) //RO -//***************************I_CF_3 -#define DisableAdjacentPulseWidth(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,5,val) //1 disable -#define DisablePulseWidthAdjust(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,4,val) //1 disable -#define UseOneRX(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,1,val) //0 use two RX -#define SlowIRRXLowActive(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_3,0,val) //0 show RX high=1 in SIR -//***************************H_CT -#define EnAllInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,7,val) -#define TXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,6,val) -#define RXStart(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,5,val) -#define ClearRXInt(BaseAddr,val) WriteRegBit(BaseAddr,H_CT,4,val) // 1 clear -//*****************H_ST -#define IsRXInt(BaseAddr) CheckRegBit(BaseAddr,H_ST,4) -#define GetIntIndentify(BaseAddr) ((ReadReg(BaseAddr,H_ST)&0xf1) >>1) -#define IsHostBusy(BaseAddr) CheckRegBit(BaseAddr,H_ST,0) -#define GetHostStatus(BaseAddr) ReadReg(BaseAddr,H_ST) //RO -//**************************M_CT -#define EnTXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,7,val) -#define EnRXDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,6,val) -#define SwapDMA(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,5,val) -#define EnInternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,4,val) -#define EnExternalLoop(BaseAddr,val) WriteRegBit(BaseAddr,M_CT,3,val) -//**************************TX_CT_1 -#define EnTXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,4,val) //half empty int (1 half) -#define EnTXFIFOUnderrunEOMInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,5,val) -#define EnTXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_1,6,val) //int when reach it threshold (setting by bit 4) -//**************************TX_CT_2 -#define ForceUnderrun(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,7,val) // force an underrun int -#define EnTXCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,6,val) //1 for FIR,MIR...0 (not SIR) -#define ForceBADCRC(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,5,val) //force an bad CRC -#define SendSIP(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,4,val) //send indication pulse for prevent SIR disturb -#define ClearEnTX(BaseAddr,val) WriteRegBit(BaseAddr,TX_CT_2,3,val) // opposite to EnTX -//*****************TX_ST -#define GetTXStatus(BaseAddr) ReadReg(BaseAddr,TX_ST) //RO -//**************************RX_CT -#define EnRXSpecInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,0,val) -#define EnRXFIFOReadyInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,1,val) //enable int when reach it threshold (setting by bit 7) -#define EnRXFIFOHalfLevelInt(BaseAddr,val) WriteRegBit(BaseAddr,RX_CT,7,val) //enable int when (1) half full...or (0) just not full -//*****************RX_ST -#define GetRXStatus(BaseAddr) ReadReg(BaseAddr,RX_ST) //RO -//***********************P_ADDR -#define SetPacketAddr(BaseAddr,addr) WriteReg(BaseAddr,P_ADDR,addr) -//***********************I_CF_4 -#define EnGPIOtoRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,7,val) -#define EnTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,1,val) -#define ClearTimerInt(BaseAddr,val) WriteRegBit(BaseAddr,I_CF_4,0,val) -//***********************I_T_C_L -#define WriteGIO(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,7,val) -#define ReadGIO(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,7) -#define ReadRX(BaseAddr) CheckRegBit(BaseAddr,I_T_C_L,3) //RO -#define WriteTX(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_L,0,val) -//***********************I_T_C_H -#define EnRX2(BaseAddr,val) WriteRegBit(BaseAddr,I_T_C_H,7,val) -#define ReadRX2(BaseAddr) CheckRegBit(BaseAddr,I_T_C_H,7) -//**********************Version -#define GetFIRVersion(BaseAddr) ReadReg(BaseAddr,VERSION) - - -static void SetTimer(__u16 iobase, __u8 count) -{ - EnTimerInt(iobase, OFF); - WriteReg(iobase, TIMER, count); - EnTimerInt(iobase, ON); -} - - -static void SetSendByte(__u16 iobase, __u32 count) -{ - __u32 low, high; - - if ((count & 0xf000) == 0) { - low = count & 0x00ff; - high = (count & 0x0f00) >> 8; - WriteReg(iobase, TX_C_L, low); - WriteReg(iobase, TX_C_H, high); - } -} - -static void ResetChip(__u16 iobase, __u8 type) -{ - __u8 value; - - value = (type + 2) << 4; - WriteReg(iobase, RESET, type); -} - -static int CkRxRecv(__u16 iobase, struct via_ircc_cb *self) -{ - __u8 low, high; - __u16 wTmp = 0, wTmp1 = 0, wTmp_new = 0; - - low = ReadReg(iobase, RX_C_L); - high = ReadReg(iobase, RX_C_H); - wTmp1 = high; - wTmp = (wTmp1 << 8) | low; - udelay(10); - low = ReadReg(iobase, RX_C_L); - high = ReadReg(iobase, RX_C_H); - wTmp1 = high; - wTmp_new = (wTmp1 << 8) | low; - if (wTmp_new != wTmp) - return 1; - else - return 0; - -} - -static __u16 RxCurCount(__u16 iobase, struct via_ircc_cb * self) -{ - __u8 low, high; - __u16 wTmp = 0, wTmp1 = 0; - - low = ReadReg(iobase, RX_P_L); - high = ReadReg(iobase, RX_P_H); - wTmp1 = high; - wTmp = (wTmp1 << 8) | low; - return wTmp; -} - -/* This Routine can only use in recevie_complete - * for it will update last count. - */ - -static __u16 GetRecvByte(__u16 iobase, struct via_ircc_cb * self) -{ - __u8 low, high; - __u16 wTmp, wTmp1, ret; - - low = ReadReg(iobase, RX_P_L); - high = ReadReg(iobase, RX_P_H); - wTmp1 = high; - wTmp = (wTmp1 << 8) | low; - - - if (wTmp >= self->RxLastCount) - ret = wTmp - self->RxLastCount; - else - ret = (0x8000 - self->RxLastCount) + wTmp; - self->RxLastCount = wTmp; - -/* RX_P is more actually the RX_C - low=ReadReg(iobase,RX_C_L); - high=ReadReg(iobase,RX_C_H); - - if(!(high&0xe000)) { - temp=(high<<8)+low; - return temp; - } - else return 0; -*/ - return ret; -} - -static void Sdelay(__u16 scale) -{ - __u8 bTmp; - int i, j; - - for (j = 0; j < scale; j++) { - for (i = 0; i < 0x20; i++) { - bTmp = inb(0xeb); - outb(bTmp, 0xeb); - } - } -} - -static void Tdelay(__u16 scale) -{ - __u8 bTmp; - int i, j; - - for (j = 0; j < scale; j++) { - for (i = 0; i < 0x50; i++) { - bTmp = inb(0xeb); - outb(bTmp, 0xeb); - } - } -} - - -static void ActClk(__u16 iobase, __u8 value) -{ - __u8 bTmp; - bTmp = ReadReg(iobase, 0x34); - if (value) - WriteReg(iobase, 0x34, bTmp | Clk_bit); - else - WriteReg(iobase, 0x34, bTmp & ~Clk_bit); -} - -static void ClkTx(__u16 iobase, __u8 Clk, __u8 Tx) -{ - __u8 bTmp; - - bTmp = ReadReg(iobase, 0x34); - if (Clk == 0) - bTmp &= ~Clk_bit; - else { - if (Clk == 1) - bTmp |= Clk_bit; - } - WriteReg(iobase, 0x34, bTmp); - Sdelay(1); - if (Tx == 0) - bTmp &= ~Tx_bit; - else { - if (Tx == 1) - bTmp |= Tx_bit; - } - WriteReg(iobase, 0x34, bTmp); -} - -static void Wr_Byte(__u16 iobase, __u8 data) -{ - __u8 bData = data; -// __u8 btmp; - int i; - - ClkTx(iobase, 0, 1); - - Tdelay(2); - ActClk(iobase, 1); - Tdelay(1); - - for (i = 0; i < 8; i++) { //LDN - - if ((bData >> i) & 0x01) { - ClkTx(iobase, 0, 1); //bit data = 1; - } else { - ClkTx(iobase, 0, 0); //bit data = 1; - } - Tdelay(2); - Sdelay(1); - ActClk(iobase, 1); //clk hi - Tdelay(1); - } -} - -static __u8 Rd_Indx(__u16 iobase, __u8 addr, __u8 index) -{ - __u8 data = 0, bTmp, data_bit; - int i; - - bTmp = addr | (index << 1) | 0; - ClkTx(iobase, 0, 0); - Tdelay(2); - ActClk(iobase, 1); - udelay(1); - Wr_Byte(iobase, bTmp); - Sdelay(1); - ClkTx(iobase, 0, 0); - Tdelay(2); - for (i = 0; i < 10; i++) { - ActClk(iobase, 1); - Tdelay(1); - ActClk(iobase, 0); - Tdelay(1); - ClkTx(iobase, 0, 1); - Tdelay(1); - bTmp = ReadReg(iobase, 0x34); - if (!(bTmp & Rd_Valid)) - break; - } - if (!(bTmp & Rd_Valid)) { - for (i = 0; i < 8; i++) { - ActClk(iobase, 1); - Tdelay(1); - ActClk(iobase, 0); - bTmp = ReadReg(iobase, 0x34); - data_bit = 1 << i; - if (bTmp & RxBit) - data |= data_bit; - else - data &= ~data_bit; - Tdelay(2); - } - } else { - for (i = 0; i < 2; i++) { - ActClk(iobase, 1); - Tdelay(1); - ActClk(iobase, 0); - Tdelay(2); - } - bTmp = ReadReg(iobase, 0x34); - } - for (i = 0; i < 1; i++) { - ActClk(iobase, 1); - Tdelay(1); - ActClk(iobase, 0); - Tdelay(2); - } - ClkTx(iobase, 0, 0); - Tdelay(1); - for (i = 0; i < 3; i++) { - ActClk(iobase, 1); - Tdelay(1); - ActClk(iobase, 0); - Tdelay(2); - } - return data; -} - -static void Wr_Indx(__u16 iobase, __u8 addr, __u8 index, __u8 data) -{ - int i; - __u8 bTmp; - - ClkTx(iobase, 0, 0); - udelay(2); - ActClk(iobase, 1); - udelay(1); - bTmp = addr | (index << 1) | 1; - Wr_Byte(iobase, bTmp); - Wr_Byte(iobase, data); - for (i = 0; i < 2; i++) { - ClkTx(iobase, 0, 0); - Tdelay(2); - ActClk(iobase, 1); - Tdelay(1); - } - ActClk(iobase, 0); -} - -static void ResetDongle(__u16 iobase) -{ - int i; - ClkTx(iobase, 0, 0); - Tdelay(1); - for (i = 0; i < 30; i++) { - ActClk(iobase, 1); - Tdelay(1); - ActClk(iobase, 0); - Tdelay(1); - } - ActClk(iobase, 0); -} - -static void SetSITmode(__u16 iobase) -{ - - __u8 bTmp; - - bTmp = ReadLPCReg(0x28); - WriteLPCReg(0x28, bTmp | 0x10); //select ITMOFF - bTmp = ReadReg(iobase, 0x35); - WriteReg(iobase, 0x35, bTmp | 0x40); // Driver ITMOFF - WriteReg(iobase, 0x28, bTmp | 0x80); // enable All interrupt -} - -static void SI_SetMode(__u16 iobase, int mode) -{ - //__u32 dTmp; - __u8 bTmp; - - WriteLPCReg(0x28, 0x70); // S/W Reset - SetSITmode(iobase); - ResetDongle(iobase); - udelay(10); - Wr_Indx(iobase, 0x40, 0x0, 0x17); //RX ,APEN enable,Normal power - Wr_Indx(iobase, 0x40, 0x1, mode); //Set Mode - Wr_Indx(iobase, 0x40, 0x2, 0xff); //Set power to FIR VFIR > 1m - bTmp = Rd_Indx(iobase, 0x40, 1); -} - -static void InitCard(__u16 iobase) -{ - ResetChip(iobase, 5); - WriteReg(iobase, I_ST_CT_0, 0x00); // open CHIP on - SetSIRBOF(iobase, 0xc0); // hardware default value - SetSIREOF(iobase, 0xc1); -} - -static void CommonInit(__u16 iobase) -{ -// EnTXCRC(iobase,0); - SwapDMA(iobase, OFF); - SetMaxRxPacketSize(iobase, 0x0fff); //set to max:4095 - EnRXFIFOReadyInt(iobase, OFF); - EnRXFIFOHalfLevelInt(iobase, OFF); - EnTXFIFOHalfLevelInt(iobase, OFF); - EnTXFIFOUnderrunEOMInt(iobase, ON); -// EnTXFIFOReadyInt(iobase,ON); - InvertTX(iobase, OFF); - InvertRX(iobase, OFF); -// WriteLPCReg(0xF0,0); //(if VT1211 then do this) - if (IsSIROn(iobase)) { - SIRFilter(iobase, ON); - SIRRecvAny(iobase, ON); - } else { - SIRFilter(iobase, OFF); - SIRRecvAny(iobase, OFF); - } - EnRXSpecInt(iobase, ON); - WriteReg(iobase, I_ST_CT_0, 0x80); - EnableDMA(iobase, ON); -} - -static void SetBaudRate(__u16 iobase, __u32 rate) -{ - __u8 value = 11, temp; - - if (IsSIROn(iobase)) { - switch (rate) { - case (__u32) (2400L): - value = 47; - break; - case (__u32) (9600L): - value = 11; - break; - case (__u32) (19200L): - value = 5; - break; - case (__u32) (38400L): - value = 2; - break; - case (__u32) (57600L): - value = 1; - break; - case (__u32) (115200L): - value = 0; - break; - default: - break; - } - } else if (IsMIROn(iobase)) { - value = 0; // will automatically be fixed in 1.152M - } else if (IsFIROn(iobase)) { - value = 0; // will automatically be fixed in 4M - } - temp = (ReadReg(iobase, I_CF_H_1) & 0x03); - temp |= value << 2; - WriteReg(iobase, I_CF_H_1, temp); -} - -static void SetPulseWidth(__u16 iobase, __u8 width) -{ - __u8 temp, temp1, temp2; - - temp = (ReadReg(iobase, I_CF_L_1) & 0x1f); - temp1 = (ReadReg(iobase, I_CF_H_1) & 0xfc); - temp2 = (width & 0x07) << 5; - temp |= temp2; - temp2 = (width & 0x18) >> 3; - temp1 |= temp2; - WriteReg(iobase, I_CF_L_1, temp); - WriteReg(iobase, I_CF_H_1, temp1); -} - -static void SetSendPreambleCount(__u16 iobase, __u8 count) -{ - __u8 temp; - - temp = ReadReg(iobase, I_CF_L_1) & 0xe0; - temp |= count; - WriteReg(iobase, I_CF_L_1, temp); - -} - -static void SetVFIR(__u16 BaseAddr, __u8 val) -{ - __u8 tmp; - - tmp = ReadReg(BaseAddr, I_CF_L_0); - WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); - WriteRegBit(BaseAddr, I_CF_H_0, 5, val); -} - -static void SetFIR(__u16 BaseAddr, __u8 val) -{ - __u8 tmp; - - WriteRegBit(BaseAddr, I_CF_H_0, 5, 0); - tmp = ReadReg(BaseAddr, I_CF_L_0); - WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); - WriteRegBit(BaseAddr, I_CF_L_0, 6, val); -} - -static void SetMIR(__u16 BaseAddr, __u8 val) -{ - __u8 tmp; - - WriteRegBit(BaseAddr, I_CF_H_0, 5, 0); - tmp = ReadReg(BaseAddr, I_CF_L_0); - WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); - WriteRegBit(BaseAddr, I_CF_L_0, 5, val); -} - -static void SetSIR(__u16 BaseAddr, __u8 val) -{ - __u8 tmp; - - WriteRegBit(BaseAddr, I_CF_H_0, 5, 0); - tmp = ReadReg(BaseAddr, I_CF_L_0); - WriteReg(BaseAddr, I_CF_L_0, tmp & 0x8f); - WriteRegBit(BaseAddr, I_CF_L_0, 4, val); -} - -#endif /* via_IRCC_H */ diff --git a/drivers/staging/irda/drivers/vlsi_ir.c b/drivers/staging/irda/drivers/vlsi_ir.c deleted file mode 100644 index 3dff3c55ddf5..000000000000 --- a/drivers/staging/irda/drivers/vlsi_ir.c +++ /dev/null @@ -1,1872 +0,0 @@ -/********************************************************************* - * - * vlsi_ir.c: VLSI82C147 PCI IrDA controller driver for Linux - * - * Copyright (c) 2001-2003 Martin Diehl - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/module.h> - -#define DRIVER_NAME "vlsi_ir" -#define DRIVER_VERSION "v0.5" -#define DRIVER_DESCRIPTION "IrDA SIR/MIR/FIR driver for VLSI 82C147" -#define DRIVER_AUTHOR "Martin Diehl <info@mdiehl.de>" - -MODULE_DESCRIPTION(DRIVER_DESCRIPTION); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); - -/********************************************************/ - -#include <linux/kernel.h> -#include <linux/ktime.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/math64.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> -#include <net/irda/wrapper.h> -#include <net/irda/crc.h> - -#include "vlsi_ir.h" - -/********************************************************/ - -static /* const */ char drivername[] = DRIVER_NAME; - -static const struct pci_device_id vlsi_irda_table[] = { - { - .class = PCI_CLASS_WIRELESS_IRDA << 8, - .class_mask = PCI_CLASS_SUBCLASS_MASK << 8, - .vendor = PCI_VENDOR_ID_VLSI, - .device = PCI_DEVICE_ID_VLSI_82C147, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { /* all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, vlsi_irda_table); - -/********************************************************/ - -/* clksrc: which clock source to be used - * 0: auto - try PLL, fallback to 40MHz XCLK - * 1: on-chip 48MHz PLL - * 2: external 48MHz XCLK - * 3: external 40MHz XCLK (HP OB-800) - */ - -static int clksrc = 0; /* default is 0(auto) */ -module_param(clksrc, int, 0); -MODULE_PARM_DESC(clksrc, "clock input source selection"); - -/* ringsize: size of the tx and rx descriptor rings - * independent for tx and rx - * specify as ringsize=tx[,rx] - * allowed values: 4, 8, 16, 32, 64 - * Due to the IrDA 1.x max. allowed window size=7, - * there should be no gain when using rings larger than 8 - */ - -static int ringsize[] = {8,8}; /* default is tx=8 / rx=8 */ -module_param_array(ringsize, int, NULL, 0); -MODULE_PARM_DESC(ringsize, "TX, RX ring descriptor size"); - -/* sirpulse: tuning of the SIR pulse width within IrPHY 1.3 limits - * 0: very short, 1.5us (exception: 6us at 2.4 kbaud) - * 1: nominal 3/16 bittime width - * note: IrDA compliant peer devices should be happy regardless - * which one is used. Primary goal is to save some power - * on the sender's side - at 9.6kbaud for example the short - * pulse width saves more than 90% of the transmitted IR power. - */ - -static int sirpulse = 1; /* default is 3/16 bittime */ -module_param(sirpulse, int, 0); -MODULE_PARM_DESC(sirpulse, "SIR pulse width tuning"); - -/* qos_mtt_bits: encoded min-turn-time value we require the peer device - * to use before transmitting to us. "Type 1" (per-station) - * bitfield according to IrLAP definition (section 6.6.8) - * Don't know which transceiver is used by my OB800 - the - * pretty common HP HDLS-1100 requires 1 msec - so lets use this. - */ - -static int qos_mtt_bits = 0x07; /* default is 1 ms or more */ -module_param(qos_mtt_bits, int, 0); -MODULE_PARM_DESC(qos_mtt_bits, "IrLAP bitfield representing min-turn-time"); - -/********************************************************/ - -static void vlsi_reg_debug(unsigned iobase, const char *s) -{ - int i; - - printk(KERN_DEBUG "%s: ", s); - for (i = 0; i < 0x20; i++) - printk("%02x", (unsigned)inb((iobase+i))); - printk("\n"); -} - -static void vlsi_ring_debug(struct vlsi_ring *r) -{ - struct ring_descr *rd; - unsigned i; - - printk(KERN_DEBUG "%s - ring %p / size %u / mask 0x%04x / len %u / dir %d / hw %p\n", - __func__, r, r->size, r->mask, r->len, r->dir, r->rd[0].hw); - printk(KERN_DEBUG "%s - head = %d / tail = %d\n", __func__, - atomic_read(&r->head) & r->mask, atomic_read(&r->tail) & r->mask); - for (i = 0; i < r->size; i++) { - rd = &r->rd[i]; - printk(KERN_DEBUG "%s - ring descr %u: ", __func__, i); - printk("skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw); - printk(KERN_DEBUG "%s - hw: status=%02x count=%u addr=0x%08x\n", - __func__, (unsigned) rd_get_status(rd), - (unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd)); - } -} - -/********************************************************/ - -/* needed regardless of CONFIG_PROC_FS */ -static struct proc_dir_entry *vlsi_proc_root = NULL; - -#ifdef CONFIG_PROC_FS - -static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev) -{ - unsigned iobase = pci_resource_start(pdev, 0); - unsigned i; - - seq_printf(seq, "\n%s (vid/did: [%04x:%04x])\n", - pci_name(pdev), (int)pdev->vendor, (int)pdev->device); - seq_printf(seq, "pci-power-state: %u\n", (unsigned) pdev->current_state); - seq_printf(seq, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n", - pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask); - seq_puts(seq, "hw registers: "); - for (i = 0; i < 0x20; i++) - seq_printf(seq, "%02x", (unsigned)inb((iobase+i))); - seq_putc(seq, '\n'); -} - -static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - u8 byte; - u16 word; - s32 sec, usec; - unsigned iobase = ndev->base_addr; - - seq_printf(seq, "\n%s link state: %s / %s / %s / %s\n", ndev->name, - netif_device_present(ndev) ? "attached" : "detached", - netif_running(ndev) ? "running" : "not running", - netif_carrier_ok(ndev) ? "carrier ok" : "no carrier", - netif_queue_stopped(ndev) ? "queue stopped" : "queue running"); - - if (!netif_running(ndev)) - return; - - seq_puts(seq, "\nhw-state:\n"); - pci_read_config_byte(idev->pdev, VLSI_PCI_IRMISC, &byte); - seq_printf(seq, "IRMISC:%s%s%s uart%s", - (byte&IRMISC_IRRAIL) ? " irrail" : "", - (byte&IRMISC_IRPD) ? " irpd" : "", - (byte&IRMISC_UARTTST) ? " uarttest" : "", - (byte&IRMISC_UARTEN) ? "@" : " disabled\n"); - if (byte&IRMISC_UARTEN) { - seq_printf(seq, "0x%s\n", - (byte&2) ? ((byte&1) ? "3e8" : "2e8") - : ((byte&1) ? "3f8" : "2f8")); - } - pci_read_config_byte(idev->pdev, VLSI_PCI_CLKCTL, &byte); - seq_printf(seq, "CLKCTL: PLL %s%s%s / clock %s / wakeup %s\n", - (byte&CLKCTL_PD_INV) ? "powered" : "down", - (byte&CLKCTL_LOCK) ? " locked" : "", - (byte&CLKCTL_EXTCLK) ? ((byte&CLKCTL_XCKSEL)?" / 40 MHz XCLK":" / 48 MHz XCLK") : "", - (byte&CLKCTL_CLKSTP) ? "stopped" : "running", - (byte&CLKCTL_WAKE) ? "enabled" : "disabled"); - pci_read_config_byte(idev->pdev, VLSI_PCI_MSTRPAGE, &byte); - seq_printf(seq, "MSTRPAGE: 0x%02x\n", (unsigned)byte); - - byte = inb(iobase+VLSI_PIO_IRINTR); - seq_printf(seq, "IRINTR:%s%s%s%s%s%s%s%s\n", - (byte&IRINTR_ACTEN) ? " ACTEN" : "", - (byte&IRINTR_RPKTEN) ? " RPKTEN" : "", - (byte&IRINTR_TPKTEN) ? " TPKTEN" : "", - (byte&IRINTR_OE_EN) ? " OE_EN" : "", - (byte&IRINTR_ACTIVITY) ? " ACTIVITY" : "", - (byte&IRINTR_RPKTINT) ? " RPKTINT" : "", - (byte&IRINTR_TPKTINT) ? " TPKTINT" : "", - (byte&IRINTR_OE_INT) ? " OE_INT" : ""); - word = inw(iobase+VLSI_PIO_RINGPTR); - seq_printf(seq, "RINGPTR: rx=%u / tx=%u\n", RINGPTR_GET_RX(word), RINGPTR_GET_TX(word)); - word = inw(iobase+VLSI_PIO_RINGBASE); - seq_printf(seq, "RINGBASE: busmap=0x%08x\n", - ((unsigned)word << 10)|(MSTRPAGE_VALUE<<24)); - word = inw(iobase+VLSI_PIO_RINGSIZE); - seq_printf(seq, "RINGSIZE: rx=%u / tx=%u\n", RINGSIZE_TO_RXSIZE(word), - RINGSIZE_TO_TXSIZE(word)); - - word = inw(iobase+VLSI_PIO_IRCFG); - seq_printf(seq, "IRCFG:%s%s%s%s%s%s%s%s%s%s%s%s%s\n", - (word&IRCFG_LOOP) ? " LOOP" : "", - (word&IRCFG_ENTX) ? " ENTX" : "", - (word&IRCFG_ENRX) ? " ENRX" : "", - (word&IRCFG_MSTR) ? " MSTR" : "", - (word&IRCFG_RXANY) ? " RXANY" : "", - (word&IRCFG_CRC16) ? " CRC16" : "", - (word&IRCFG_FIR) ? " FIR" : "", - (word&IRCFG_MIR) ? " MIR" : "", - (word&IRCFG_SIR) ? " SIR" : "", - (word&IRCFG_SIRFILT) ? " SIRFILT" : "", - (word&IRCFG_SIRTEST) ? " SIRTEST" : "", - (word&IRCFG_TXPOL) ? " TXPOL" : "", - (word&IRCFG_RXPOL) ? " RXPOL" : ""); - word = inw(iobase+VLSI_PIO_IRENABLE); - seq_printf(seq, "IRENABLE:%s%s%s%s%s%s%s%s\n", - (word&IRENABLE_PHYANDCLOCK) ? " PHYANDCLOCK" : "", - (word&IRENABLE_CFGER) ? " CFGERR" : "", - (word&IRENABLE_FIR_ON) ? " FIR_ON" : "", - (word&IRENABLE_MIR_ON) ? " MIR_ON" : "", - (word&IRENABLE_SIR_ON) ? " SIR_ON" : "", - (word&IRENABLE_ENTXST) ? " ENTXST" : "", - (word&IRENABLE_ENRXST) ? " ENRXST" : "", - (word&IRENABLE_CRC16_ON) ? " CRC16_ON" : ""); - word = inw(iobase+VLSI_PIO_PHYCTL); - seq_printf(seq, "PHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n", - (unsigned)PHYCTL_TO_BAUD(word), - (unsigned)PHYCTL_TO_PLSWID(word), - (unsigned)PHYCTL_TO_PREAMB(word)); - word = inw(iobase+VLSI_PIO_NPHYCTL); - seq_printf(seq, "NPHYCTL: baud-divisor=%u / pulsewidth=%u / preamble=%u\n", - (unsigned)PHYCTL_TO_BAUD(word), - (unsigned)PHYCTL_TO_PLSWID(word), - (unsigned)PHYCTL_TO_PREAMB(word)); - word = inw(iobase+VLSI_PIO_MAXPKT); - seq_printf(seq, "MAXPKT: max. rx packet size = %u\n", word); - word = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; - seq_printf(seq, "RCVBCNT: rx-fifo filling level = %u\n", word); - - seq_puts(seq, "\nsw-state:\n"); - seq_printf(seq, "IrPHY setup: %d baud - %s encoding\n", idev->baud, - (idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR")); - sec = div_s64_rem(ktime_us_delta(ktime_get(), idev->last_rx), - USEC_PER_SEC, &usec); - seq_printf(seq, "last rx: %ul.%06u sec\n", sec, usec); - - seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu", - ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors, - ndev->stats.rx_dropped); - seq_printf(seq, " / overrun=%lu / length=%lu / frame=%lu / crc=%lu\n", - ndev->stats.rx_over_errors, ndev->stats.rx_length_errors, - ndev->stats.rx_frame_errors, ndev->stats.rx_crc_errors); - seq_printf(seq, "TX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu / fifo=%lu\n", - ndev->stats.tx_packets, ndev->stats.tx_bytes, ndev->stats.tx_errors, - ndev->stats.tx_dropped, ndev->stats.tx_fifo_errors); - -} - -static void vlsi_proc_ring(struct seq_file *seq, struct vlsi_ring *r) -{ - struct ring_descr *rd; - unsigned i, j; - int h, t; - - seq_printf(seq, "size %u / mask 0x%04x / len %u / dir %d / hw %p\n", - r->size, r->mask, r->len, r->dir, r->rd[0].hw); - h = atomic_read(&r->head) & r->mask; - t = atomic_read(&r->tail) & r->mask; - seq_printf(seq, "head = %d / tail = %d ", h, t); - if (h == t) - seq_puts(seq, "(empty)\n"); - else { - if (((t+1)&r->mask) == h) - seq_puts(seq, "(full)\n"); - else - seq_printf(seq, "(level = %d)\n", ((unsigned)(t-h) & r->mask)); - rd = &r->rd[h]; - j = (unsigned) rd_get_count(rd); - seq_printf(seq, "current: rd = %d / status = %02x / len = %u\n", - h, (unsigned)rd_get_status(rd), j); - if (j > 0) { - seq_printf(seq, " data: %*ph\n", - min_t(unsigned, j, 20), rd->buf); - } - } - for (i = 0; i < r->size; i++) { - rd = &r->rd[i]; - seq_printf(seq, "> ring descr %u: ", i); - seq_printf(seq, "skb=%p data=%p hw=%p\n", rd->skb, rd->buf, rd->hw); - seq_printf(seq, " hw: status=%02x count=%u busaddr=0x%08x\n", - (unsigned) rd_get_status(rd), - (unsigned) rd_get_count(rd), (unsigned) rd_get_addr(rd)); - } -} - -static int vlsi_seq_show(struct seq_file *seq, void *v) -{ - struct net_device *ndev = seq->private; - vlsi_irda_dev_t *idev = netdev_priv(ndev); - unsigned long flags; - - seq_printf(seq, "\n%s %s\n\n", DRIVER_NAME, DRIVER_VERSION); - seq_printf(seq, "clksrc: %s\n", - (clksrc>=2) ? ((clksrc==3)?"40MHz XCLK":"48MHz XCLK") - : ((clksrc==1)?"48MHz PLL":"autodetect")); - seq_printf(seq, "ringsize: tx=%d / rx=%d\n", - ringsize[0], ringsize[1]); - seq_printf(seq, "sirpulse: %s\n", (sirpulse)?"3/16 bittime":"short"); - seq_printf(seq, "qos_mtt_bits: 0x%02x\n", (unsigned)qos_mtt_bits); - - spin_lock_irqsave(&idev->lock, flags); - if (idev->pdev != NULL) { - vlsi_proc_pdev(seq, idev->pdev); - - if (idev->pdev->current_state == 0) - vlsi_proc_ndev(seq, ndev); - else - seq_printf(seq, "\nPCI controller down - resume_ok = %d\n", - idev->resume_ok); - if (netif_running(ndev) && idev->rx_ring && idev->tx_ring) { - seq_puts(seq, "\n--------- RX ring -----------\n\n"); - vlsi_proc_ring(seq, idev->rx_ring); - seq_puts(seq, "\n--------- TX ring -----------\n\n"); - vlsi_proc_ring(seq, idev->tx_ring); - } - } - seq_putc(seq, '\n'); - spin_unlock_irqrestore(&idev->lock, flags); - - return 0; -} - -static int vlsi_seq_open(struct inode *inode, struct file *file) -{ - return single_open(file, vlsi_seq_show, PDE_DATA(inode)); -} - -static const struct file_operations vlsi_proc_fops = { - .owner = THIS_MODULE, - .open = vlsi_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#define VLSI_PROC_FOPS (&vlsi_proc_fops) - -#else /* CONFIG_PROC_FS */ -#define VLSI_PROC_FOPS NULL -#endif - -/********************************************************/ - -static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr_hw *hwmap, - unsigned size, unsigned len, int dir) -{ - struct vlsi_ring *r; - struct ring_descr *rd; - unsigned i, j; - dma_addr_t busaddr; - - if (!size || ((size-1)&size)!=0) /* must be >0 and power of 2 */ - return NULL; - - r = kmalloc(sizeof(*r) + size * sizeof(struct ring_descr), GFP_KERNEL); - if (!r) - return NULL; - memset(r, 0, sizeof(*r)); - - r->pdev = pdev; - r->dir = dir; - r->len = len; - r->rd = (struct ring_descr *)(r+1); - r->mask = size - 1; - r->size = size; - atomic_set(&r->head, 0); - atomic_set(&r->tail, 0); - - for (i = 0; i < size; i++) { - rd = r->rd + i; - memset(rd, 0, sizeof(*rd)); - rd->hw = hwmap + i; - rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA); - if (rd->buf) - busaddr = pci_map_single(pdev, rd->buf, len, dir); - if (rd->buf == NULL || pci_dma_mapping_error(pdev, busaddr)) { - if (rd->buf) { - net_err_ratelimited("%s: failed to create PCI-MAP for %p\n", - __func__, rd->buf); - kfree(rd->buf); - rd->buf = NULL; - } - for (j = 0; j < i; j++) { - rd = r->rd + j; - busaddr = rd_get_addr(rd); - rd_set_addr_status(rd, 0, 0); - pci_unmap_single(pdev, busaddr, len, dir); - kfree(rd->buf); - rd->buf = NULL; - } - kfree(r); - return NULL; - } - rd_set_addr_status(rd, busaddr, 0); - /* initially, the dma buffer is owned by the CPU */ - rd->skb = NULL; - } - return r; -} - -static int vlsi_free_ring(struct vlsi_ring *r) -{ - struct ring_descr *rd; - unsigned i; - dma_addr_t busaddr; - - for (i = 0; i < r->size; i++) { - rd = r->rd + i; - if (rd->skb) - dev_kfree_skb_any(rd->skb); - busaddr = rd_get_addr(rd); - rd_set_addr_status(rd, 0, 0); - if (busaddr) - pci_unmap_single(r->pdev, busaddr, r->len, r->dir); - kfree(rd->buf); - } - kfree(r); - return 0; -} - -static int vlsi_create_hwif(vlsi_irda_dev_t *idev) -{ - char *ringarea; - struct ring_descr_hw *hwmap; - - idev->virtaddr = NULL; - idev->busaddr = 0; - - ringarea = pci_zalloc_consistent(idev->pdev, HW_RING_AREA_SIZE, - &idev->busaddr); - if (!ringarea) - goto out; - - hwmap = (struct ring_descr_hw *)ringarea; - idev->rx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[1], - XFER_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (idev->rx_ring == NULL) - goto out_unmap; - - hwmap += MAX_RING_DESCR; - idev->tx_ring = vlsi_alloc_ring(idev->pdev, hwmap, ringsize[0], - XFER_BUF_SIZE, PCI_DMA_TODEVICE); - if (idev->tx_ring == NULL) - goto out_free_rx; - - idev->virtaddr = ringarea; - return 0; - -out_free_rx: - vlsi_free_ring(idev->rx_ring); -out_unmap: - idev->rx_ring = idev->tx_ring = NULL; - pci_free_consistent(idev->pdev, HW_RING_AREA_SIZE, ringarea, idev->busaddr); - idev->busaddr = 0; -out: - return -ENOMEM; -} - -static int vlsi_destroy_hwif(vlsi_irda_dev_t *idev) -{ - vlsi_free_ring(idev->rx_ring); - vlsi_free_ring(idev->tx_ring); - idev->rx_ring = idev->tx_ring = NULL; - - if (idev->busaddr) - pci_free_consistent(idev->pdev,HW_RING_AREA_SIZE,idev->virtaddr,idev->busaddr); - - idev->virtaddr = NULL; - idev->busaddr = 0; - - return 0; -} - -/********************************************************/ - -static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) -{ - u16 status; - int crclen, len = 0; - struct sk_buff *skb; - int ret = 0; - struct net_device *ndev = pci_get_drvdata(r->pdev); - vlsi_irda_dev_t *idev = netdev_priv(ndev); - - pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); - /* dma buffer now owned by the CPU */ - status = rd_get_status(rd); - if (status & RD_RX_ERROR) { - if (status & RD_RX_OVER) - ret |= VLSI_RX_OVER; - if (status & RD_RX_LENGTH) - ret |= VLSI_RX_LENGTH; - if (status & RD_RX_PHYERR) - ret |= VLSI_RX_FRAME; - if (status & RD_RX_CRCERR) - ret |= VLSI_RX_CRC; - goto done; - } - - len = rd_get_count(rd); - crclen = (idev->mode==IFF_FIR) ? sizeof(u32) : sizeof(u16); - len -= crclen; /* remove trailing CRC */ - if (len <= 0) { - pr_debug("%s: strange frame (len=%d)\n", __func__, len); - ret |= VLSI_RX_DROP; - goto done; - } - - if (idev->mode == IFF_SIR) { /* hw checks CRC in MIR, FIR mode */ - - /* rd->buf is a streaming PCI_DMA_FROMDEVICE map. Doing the - * endian-adjustment there just in place will dirty a cache line - * which belongs to the map and thus we must be sure it will - * get flushed before giving the buffer back to hardware. - * vlsi_fill_rx() will do this anyway - but here we rely on. - */ - le16_to_cpus(rd->buf+len); - if (irda_calc_crc16(INIT_FCS,rd->buf,len+crclen) != GOOD_FCS) { - pr_debug("%s: crc error\n", __func__); - ret |= VLSI_RX_CRC; - goto done; - } - } - - if (!rd->skb) { - net_warn_ratelimited("%s: rx packet lost\n", __func__); - ret |= VLSI_RX_DROP; - goto done; - } - - skb = rd->skb; - rd->skb = NULL; - skb->dev = ndev; - skb_put_data(skb, rd->buf, len); - skb_reset_mac_header(skb); - if (in_interrupt()) - netif_rx(skb); - else - netif_rx_ni(skb); - -done: - rd_set_status(rd, 0); - rd_set_count(rd, 0); - /* buffer still owned by CPU */ - - return (ret) ? -ret : len; -} - -static void vlsi_fill_rx(struct vlsi_ring *r) -{ - struct ring_descr *rd; - - for (rd = ring_last(r); rd != NULL; rd = ring_put(r)) { - if (rd_is_active(rd)) { - net_warn_ratelimited("%s: driver bug: rx descr race with hw\n", - __func__); - vlsi_ring_debug(r); - break; - } - if (!rd->skb) { - rd->skb = dev_alloc_skb(IRLAP_SKB_ALLOCSIZE); - if (rd->skb) { - skb_reserve(rd->skb,1); - rd->skb->protocol = htons(ETH_P_IRDA); - } - else - break; /* probably not worth logging? */ - } - /* give dma buffer back to busmaster */ - pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); - rd_activate(rd); - } -} - -static void vlsi_rx_interrupt(struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - struct vlsi_ring *r = idev->rx_ring; - struct ring_descr *rd; - int ret; - - for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { - - if (rd_is_active(rd)) - break; - - ret = vlsi_process_rx(r, rd); - - if (ret < 0) { - ret = -ret; - ndev->stats.rx_errors++; - if (ret & VLSI_RX_DROP) - ndev->stats.rx_dropped++; - if (ret & VLSI_RX_OVER) - ndev->stats.rx_over_errors++; - if (ret & VLSI_RX_LENGTH) - ndev->stats.rx_length_errors++; - if (ret & VLSI_RX_FRAME) - ndev->stats.rx_frame_errors++; - if (ret & VLSI_RX_CRC) - ndev->stats.rx_crc_errors++; - } - else if (ret > 0) { - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += ret; - } - } - - idev->last_rx = ktime_get(); /* remember "now" for later mtt delay */ - - vlsi_fill_rx(r); - - if (ring_first(r) == NULL) { - /* we are in big trouble, if this should ever happen */ - net_err_ratelimited("%s: rx ring exhausted!\n", __func__); - vlsi_ring_debug(r); - } - else - outw(0, ndev->base_addr+VLSI_PIO_PROMPT); -} - -/* caller must have stopped the controller from busmastering */ - -static void vlsi_unarm_rx(vlsi_irda_dev_t *idev) -{ - struct net_device *ndev = pci_get_drvdata(idev->pdev); - struct vlsi_ring *r = idev->rx_ring; - struct ring_descr *rd; - int ret; - - for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { - - ret = 0; - if (rd_is_active(rd)) { - rd_set_status(rd, 0); - if (rd_get_count(rd)) { - pr_debug("%s - dropping rx packet\n", __func__); - ret = -VLSI_RX_DROP; - } - rd_set_count(rd, 0); - pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); - if (rd->skb) { - dev_kfree_skb_any(rd->skb); - rd->skb = NULL; - } - } - else - ret = vlsi_process_rx(r, rd); - - if (ret < 0) { - ret = -ret; - ndev->stats.rx_errors++; - if (ret & VLSI_RX_DROP) - ndev->stats.rx_dropped++; - if (ret & VLSI_RX_OVER) - ndev->stats.rx_over_errors++; - if (ret & VLSI_RX_LENGTH) - ndev->stats.rx_length_errors++; - if (ret & VLSI_RX_FRAME) - ndev->stats.rx_frame_errors++; - if (ret & VLSI_RX_CRC) - ndev->stats.rx_crc_errors++; - } - else if (ret > 0) { - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += ret; - } - } -} - -/********************************************************/ - -static int vlsi_process_tx(struct vlsi_ring *r, struct ring_descr *rd) -{ - u16 status; - int len; - int ret; - - pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); - /* dma buffer now owned by the CPU */ - status = rd_get_status(rd); - if (status & RD_TX_UNDRN) - ret = VLSI_TX_FIFO; - else - ret = 0; - rd_set_status(rd, 0); - - if (rd->skb) { - len = rd->skb->len; - dev_kfree_skb_any(rd->skb); - rd->skb = NULL; - } - else /* tx-skb already freed? - should never happen */ - len = rd_get_count(rd); /* incorrect for SIR! (due to wrapping) */ - - rd_set_count(rd, 0); - /* dma buffer still owned by the CPU */ - - return (ret) ? -ret : len; -} - -static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) -{ - u16 nphyctl; - u16 config; - unsigned mode; - int ret; - int baudrate; - int fifocnt; - - baudrate = idev->new_baud; - pr_debug("%s: %d -> %d\n", __func__, idev->baud, idev->new_baud); - if (baudrate == 4000000) { - mode = IFF_FIR; - config = IRCFG_FIR; - nphyctl = PHYCTL_FIR; - } - else if (baudrate == 1152000) { - mode = IFF_MIR; - config = IRCFG_MIR | IRCFG_CRC16; - nphyctl = PHYCTL_MIR(clksrc==3); - } - else { - mode = IFF_SIR; - config = IRCFG_SIR | IRCFG_SIRFILT | IRCFG_RXANY; - switch(baudrate) { - default: - net_warn_ratelimited("%s: undefined baudrate %d - fallback to 9600!\n", - __func__, baudrate); - baudrate = 9600; - /* fallthru */ - case 2400: - case 9600: - case 19200: - case 38400: - case 57600: - case 115200: - nphyctl = PHYCTL_SIR(baudrate,sirpulse,clksrc==3); - break; - } - } - config |= IRCFG_MSTR | IRCFG_ENRX; - - fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; - if (fifocnt != 0) { - pr_debug("%s: rx fifo not empty(%d)\n", __func__, fifocnt); - } - - outw(0, iobase+VLSI_PIO_IRENABLE); - outw(config, iobase+VLSI_PIO_IRCFG); - outw(nphyctl, iobase+VLSI_PIO_NPHYCTL); - wmb(); - outw(IRENABLE_PHYANDCLOCK, iobase+VLSI_PIO_IRENABLE); - mb(); - - udelay(1); /* chip applies IRCFG on next rising edge of its 8MHz clock */ - - /* read back settings for validation */ - - config = inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_MASK; - - if (mode == IFF_FIR) - config ^= IRENABLE_FIR_ON; - else if (mode == IFF_MIR) - config ^= (IRENABLE_MIR_ON|IRENABLE_CRC16_ON); - else - config ^= IRENABLE_SIR_ON; - - if (config != (IRENABLE_PHYANDCLOCK|IRENABLE_ENRXST)) { - net_warn_ratelimited("%s: failed to set %s mode!\n", - __func__, - mode == IFF_SIR ? "SIR" : - mode == IFF_MIR ? "MIR" : "FIR"); - ret = -1; - } - else { - if (inw(iobase+VLSI_PIO_PHYCTL) != nphyctl) { - net_warn_ratelimited("%s: failed to apply baudrate %d\n", - __func__, baudrate); - ret = -1; - } - else { - idev->mode = mode; - idev->baud = baudrate; - idev->new_baud = 0; - ret = 0; - } - } - - if (ret) - vlsi_reg_debug(iobase,__func__); - - return ret; -} - -static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, - struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - struct vlsi_ring *r = idev->tx_ring; - struct ring_descr *rd; - unsigned long flags; - unsigned iobase = ndev->base_addr; - u8 status; - u16 config; - int mtt, diff; - int len, speed; - char *msg = NULL; - - speed = irda_get_next_speed(skb); - spin_lock_irqsave(&idev->lock, flags); - if (speed != -1 && speed != idev->baud) { - netif_stop_queue(ndev); - idev->new_baud = speed; - status = RD_TX_CLRENTX; /* stop tx-ring after this frame */ - } - else - status = 0; - - if (skb->len == 0) { - /* handle zero packets - should be speed change */ - if (status == 0) { - msg = "bogus zero-length packet"; - goto drop_unlock; - } - - /* due to the completely asynch tx operation we might have - * IrLAP racing with the hardware here, f.e. if the controller - * is just sending the last packet with current speed while - * the LAP is already switching the speed using synchronous - * len=0 packet. Immediate execution would lead to hw lockup - * requiring a powercycle to reset. Good candidate to trigger - * this is the final UA:RSP packet after receiving a DISC:CMD - * when getting the LAP down. - * Note that we are not protected by the queue_stop approach - * because the final UA:RSP arrives _without_ request to apply - * new-speed-after-this-packet - hence the driver doesn't know - * this was the last packet and doesn't stop the queue. So the - * forced switch to default speed from LAP gets through as fast - * as only some 10 usec later while the UA:RSP is still processed - * by the hardware and we would get screwed. - */ - - if (ring_first(idev->tx_ring) == NULL) { - /* no race - tx-ring already empty */ - vlsi_set_baud(idev, iobase); - netif_wake_queue(ndev); - } - else - ; - /* keep the speed change pending like it would - * for any len>0 packet. tx completion interrupt - * will apply it when the tx ring becomes empty. - */ - spin_unlock_irqrestore(&idev->lock, flags); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - /* sanity checks - simply drop the packet */ - - rd = ring_last(r); - if (!rd) { - msg = "ring full, but queue wasn't stopped"; - goto drop_unlock; - } - - if (rd_is_active(rd)) { - msg = "entry still owned by hw"; - goto drop_unlock; - } - - if (!rd->buf) { - msg = "tx ring entry without pci buffer"; - goto drop_unlock; - } - - if (rd->skb) { - msg = "ring entry with old skb still attached"; - goto drop_unlock; - } - - /* no need for serialization or interrupt disable during mtt */ - spin_unlock_irqrestore(&idev->lock, flags); - - if ((mtt = irda_get_mtt(skb)) > 0) { - diff = ktime_us_delta(ktime_get(), idev->last_rx); - if (mtt > diff) - udelay(mtt - diff); - /* must not sleep here - called under netif_tx_lock! */ - } - - /* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu() - * after subsequent tx-completion - */ - - if (idev->mode == IFF_SIR) { - status |= RD_TX_DISCRC; /* no hw-crc creation */ - len = async_wrap_skb(skb, rd->buf, r->len); - - /* Some rare worst case situation in SIR mode might lead to - * potential buffer overflow. The wrapper detects this, returns - * with a shortened frame (without FCS/EOF) but doesn't provide - * any error indication about the invalid packet which we are - * going to transmit. - * Therefore we log if the buffer got filled to the point, where the - * wrapper would abort, i.e. when there are less than 5 bytes left to - * allow appending the FCS/EOF. - */ - - if (len >= r->len-5) - net_warn_ratelimited("%s: possible buffer overflow with SIR wrapping!\n", - __func__); - } - else { - /* hw deals with MIR/FIR mode wrapping */ - status |= RD_TX_PULSE; /* send 2 us highspeed indication pulse */ - len = skb->len; - if (len > r->len) { - msg = "frame exceeds tx buffer length"; - goto drop; - } - else - skb_copy_from_linear_data(skb, rd->buf, len); - } - - rd->skb = skb; /* remember skb for tx-complete stats */ - - rd_set_count(rd, len); - rd_set_status(rd, status); /* not yet active! */ - - /* give dma buffer back to busmaster-hw (flush caches to make - * CPU-driven changes visible from the pci bus). - */ - - pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); - -/* Switching to TX mode here races with the controller - * which may stop TX at any time when fetching an inactive descriptor - * or one with CLR_ENTX set. So we switch on TX only, if TX was not running - * _after_ the new descriptor was activated on the ring. This ensures - * we will either find TX already stopped or we can be sure, there - * will be a TX-complete interrupt even if the chip stopped doing - * TX just after we found it still running. The ISR will then find - * the non-empty ring and restart TX processing. The enclosing - * spinlock provides the correct serialization to prevent race with isr. - */ - - spin_lock_irqsave(&idev->lock,flags); - - rd_activate(rd); - - if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) { - int fifocnt; - - fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; - if (fifocnt != 0) { - pr_debug("%s: rx fifo not empty(%d)\n", - __func__, fifocnt); - } - - config = inw(iobase+VLSI_PIO_IRCFG); - mb(); - outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG); - wmb(); - outw(0, iobase+VLSI_PIO_PROMPT); - } - - if (ring_put(r) == NULL) { - netif_stop_queue(ndev); - pr_debug("%s: tx ring full - queue stopped\n", __func__); - } - spin_unlock_irqrestore(&idev->lock, flags); - - return NETDEV_TX_OK; - -drop_unlock: - spin_unlock_irqrestore(&idev->lock, flags); -drop: - net_warn_ratelimited("%s: dropping packet - %s\n", __func__, msg); - dev_kfree_skb_any(skb); - ndev->stats.tx_errors++; - ndev->stats.tx_dropped++; - /* Don't even think about returning NET_XMIT_DROP (=1) here! - * In fact any retval!=0 causes the packet scheduler to requeue the - * packet for later retry of transmission - which isn't exactly - * what we want after we've just called dev_kfree_skb_any ;-) - */ - return NETDEV_TX_OK; -} - -static void vlsi_tx_interrupt(struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - struct vlsi_ring *r = idev->tx_ring; - struct ring_descr *rd; - unsigned iobase; - int ret; - u16 config; - - for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { - - if (rd_is_active(rd)) - break; - - ret = vlsi_process_tx(r, rd); - - if (ret < 0) { - ret = -ret; - ndev->stats.tx_errors++; - if (ret & VLSI_TX_DROP) - ndev->stats.tx_dropped++; - if (ret & VLSI_TX_FIFO) - ndev->stats.tx_fifo_errors++; - } - else if (ret > 0){ - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += ret; - } - } - - iobase = ndev->base_addr; - - if (idev->new_baud && rd == NULL) /* tx ring empty and speed change pending */ - vlsi_set_baud(idev, iobase); - - config = inw(iobase+VLSI_PIO_IRCFG); - if (rd == NULL) /* tx ring empty: re-enable rx */ - outw((config & ~IRCFG_ENTX) | IRCFG_ENRX, iobase+VLSI_PIO_IRCFG); - - else if (!(inw(iobase+VLSI_PIO_IRENABLE) & IRENABLE_ENTXST)) { - int fifocnt; - - fifocnt = inw(iobase+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; - if (fifocnt != 0) { - pr_debug("%s: rx fifo not empty(%d)\n", - __func__, fifocnt); - } - outw(config | IRCFG_ENTX, iobase+VLSI_PIO_IRCFG); - } - - outw(0, iobase+VLSI_PIO_PROMPT); - - if (netif_queue_stopped(ndev) && !idev->new_baud) { - netif_wake_queue(ndev); - pr_debug("%s: queue awoken\n", __func__); - } -} - -/* caller must have stopped the controller from busmastering */ - -static void vlsi_unarm_tx(vlsi_irda_dev_t *idev) -{ - struct net_device *ndev = pci_get_drvdata(idev->pdev); - struct vlsi_ring *r = idev->tx_ring; - struct ring_descr *rd; - int ret; - - for (rd = ring_first(r); rd != NULL; rd = ring_get(r)) { - - ret = 0; - if (rd_is_active(rd)) { - rd_set_status(rd, 0); - rd_set_count(rd, 0); - pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); - if (rd->skb) { - dev_kfree_skb_any(rd->skb); - rd->skb = NULL; - } - pr_debug("%s - dropping tx packet\n", __func__); - ret = -VLSI_TX_DROP; - } - else - ret = vlsi_process_tx(r, rd); - - if (ret < 0) { - ret = -ret; - ndev->stats.tx_errors++; - if (ret & VLSI_TX_DROP) - ndev->stats.tx_dropped++; - if (ret & VLSI_TX_FIFO) - ndev->stats.tx_fifo_errors++; - } - else if (ret > 0){ - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += ret; - } - } - -} - -/********************************************************/ - -static int vlsi_start_clock(struct pci_dev *pdev) -{ - u8 clkctl, lock; - int i, count; - - if (clksrc < 2) { /* auto or PLL: try PLL */ - clkctl = CLKCTL_PD_INV | CLKCTL_CLKSTP; - pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); - - /* procedure to detect PLL lock synchronisation: - * after 0.5 msec initial delay we expect to find 3 PLL lock - * indications within 10 msec for successful PLL detection. - */ - udelay(500); - count = 0; - for (i = 500; i <= 10000; i += 50) { /* max 10 msec */ - pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &lock); - if (lock&CLKCTL_LOCK) { - if (++count >= 3) - break; - } - udelay(50); - } - if (count < 3) { - if (clksrc == 1) { /* explicitly asked for PLL hence bail out */ - net_err_ratelimited("%s: no PLL or failed to lock!\n", - __func__); - clkctl = CLKCTL_CLKSTP; - pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); - return -1; - } - else /* was: clksrc=0(auto) */ - clksrc = 3; /* fallback to 40MHz XCLK (OB800) */ - - pr_debug("%s: PLL not locked, fallback to clksrc=%d\n", - __func__, clksrc); - } - else - clksrc = 1; /* got successful PLL lock */ - } - - if (clksrc != 1) { - /* we get here if either no PLL detected in auto-mode or - an external clock source was explicitly specified */ - - clkctl = CLKCTL_EXTCLK | CLKCTL_CLKSTP; - if (clksrc == 3) - clkctl |= CLKCTL_XCKSEL; - pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); - - /* no way to test for working XCLK */ - } - else - pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl); - - /* ok, now going to connect the chip with the clock source */ - - clkctl &= ~CLKCTL_CLKSTP; - pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); - - return 0; -} - -static void vlsi_stop_clock(struct pci_dev *pdev) -{ - u8 clkctl; - - /* disconnect chip from clock source */ - pci_read_config_byte(pdev, VLSI_PCI_CLKCTL, &clkctl); - clkctl |= CLKCTL_CLKSTP; - pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); - - /* disable all clock sources */ - clkctl &= ~(CLKCTL_EXTCLK | CLKCTL_PD_INV); - pci_write_config_byte(pdev, VLSI_PCI_CLKCTL, clkctl); -} - -/********************************************************/ - -/* writing all-zero to the VLSI PCI IO register area seems to prevent - * some occasional situations where the hardware fails (symptoms are - * what appears as stalled tx/rx state machines, i.e. everything ok for - * receive or transmit but hw makes no progress or is unable to access - * the bus memory locations). - * Best place to call this is immediately after/before the internal clock - * gets started/stopped. - */ - -static inline void vlsi_clear_regs(unsigned iobase) -{ - unsigned i; - const unsigned chip_io_extent = 32; - - for (i = 0; i < chip_io_extent; i += sizeof(u16)) - outw(0, iobase + i); -} - -static int vlsi_init_chip(struct pci_dev *pdev) -{ - struct net_device *ndev = pci_get_drvdata(pdev); - vlsi_irda_dev_t *idev = netdev_priv(ndev); - unsigned iobase; - u16 ptr; - - /* start the clock and clean the registers */ - - if (vlsi_start_clock(pdev)) { - net_err_ratelimited("%s: no valid clock source\n", __func__); - return -1; - } - iobase = ndev->base_addr; - vlsi_clear_regs(iobase); - - outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* w/c pending IRQ, disable all INT */ - - outw(0, iobase+VLSI_PIO_IRENABLE); /* disable IrPHY-interface */ - - /* disable everything, particularly IRCFG_MSTR - (also resetting the RING_PTR) */ - - outw(0, iobase+VLSI_PIO_IRCFG); - wmb(); - - outw(MAX_PACKET_LENGTH, iobase+VLSI_PIO_MAXPKT); /* max possible value=0x0fff */ - - outw(BUS_TO_RINGBASE(idev->busaddr), iobase+VLSI_PIO_RINGBASE); - - outw(TX_RX_TO_RINGSIZE(idev->tx_ring->size, idev->rx_ring->size), - iobase+VLSI_PIO_RINGSIZE); - - ptr = inw(iobase+VLSI_PIO_RINGPTR); - atomic_set(&idev->rx_ring->head, RINGPTR_GET_RX(ptr)); - atomic_set(&idev->rx_ring->tail, RINGPTR_GET_RX(ptr)); - atomic_set(&idev->tx_ring->head, RINGPTR_GET_TX(ptr)); - atomic_set(&idev->tx_ring->tail, RINGPTR_GET_TX(ptr)); - - vlsi_set_baud(idev, iobase); /* idev->new_baud used as provided by caller */ - - outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); /* just in case - w/c pending IRQ's */ - wmb(); - - /* DO NOT BLINDLY ENABLE IRINTR_ACTEN! - * basically every received pulse fires an ACTIVITY-INT - * leading to >>1000 INT's per second instead of few 10 - */ - - outb(IRINTR_RPKTEN|IRINTR_TPKTEN, iobase+VLSI_PIO_IRINTR); - - return 0; -} - -static int vlsi_start_hw(vlsi_irda_dev_t *idev) -{ - struct pci_dev *pdev = idev->pdev; - struct net_device *ndev = pci_get_drvdata(pdev); - unsigned iobase = ndev->base_addr; - u8 byte; - - /* we don't use the legacy UART, disable its address decoding */ - - pci_read_config_byte(pdev, VLSI_PCI_IRMISC, &byte); - byte &= ~(IRMISC_UARTEN | IRMISC_UARTTST); - pci_write_config_byte(pdev, VLSI_PCI_IRMISC, byte); - - /* enable PCI busmaster access to our 16MB page */ - - pci_write_config_byte(pdev, VLSI_PCI_MSTRPAGE, MSTRPAGE_VALUE); - pci_set_master(pdev); - - if (vlsi_init_chip(pdev) < 0) { - pci_disable_device(pdev); - return -1; - } - - vlsi_fill_rx(idev->rx_ring); - - idev->last_rx = ktime_get(); /* first mtt may start from now on */ - - outw(0, iobase+VLSI_PIO_PROMPT); /* kick hw state machine */ - - return 0; -} - -static int vlsi_stop_hw(vlsi_irda_dev_t *idev) -{ - struct pci_dev *pdev = idev->pdev; - struct net_device *ndev = pci_get_drvdata(pdev); - unsigned iobase = ndev->base_addr; - unsigned long flags; - - spin_lock_irqsave(&idev->lock,flags); - outw(0, iobase+VLSI_PIO_IRENABLE); - outw(0, iobase+VLSI_PIO_IRCFG); /* disable everything */ - - /* disable and w/c irqs */ - outb(0, iobase+VLSI_PIO_IRINTR); - wmb(); - outb(IRINTR_INT_MASK, iobase+VLSI_PIO_IRINTR); - spin_unlock_irqrestore(&idev->lock,flags); - - vlsi_unarm_tx(idev); - vlsi_unarm_rx(idev); - - vlsi_clear_regs(iobase); - vlsi_stop_clock(pdev); - - pci_disable_device(pdev); - - return 0; -} - -/**************************************************************/ - -static void vlsi_tx_timeout(struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - - - vlsi_reg_debug(ndev->base_addr, __func__); - vlsi_ring_debug(idev->tx_ring); - - if (netif_running(ndev)) - netif_stop_queue(ndev); - - vlsi_stop_hw(idev); - - /* now simply restart the whole thing */ - - if (!idev->new_baud) - idev->new_baud = idev->baud; /* keep current baudrate */ - - if (vlsi_start_hw(idev)) - net_err_ratelimited("%s: failed to restart hw - %s(%s) unusable!\n", - __func__, pci_name(idev->pdev), ndev->name); - else - netif_start_queue(ndev); -} - -static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - struct if_irda_req *irq = (struct if_irda_req *) rq; - unsigned long flags; - u16 fifocnt; - int ret = 0; - - switch (cmd) { - case SIOCSBANDWIDTH: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - spin_lock_irqsave(&idev->lock, flags); - idev->new_baud = irq->ifr_baudrate; - /* when called from userland there might be a minor race window here - * if the stack tries to change speed concurrently - which would be - * pretty strange anyway with the userland having full control... - */ - vlsi_set_baud(idev, ndev->base_addr); - spin_unlock_irqrestore(&idev->lock, flags); - break; - case SIOCSMEDIABUSY: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - irda_device_set_media_busy(ndev, TRUE); - break; - case SIOCGRECEIVING: - /* the best we can do: check whether there are any bytes in rx fifo. - * The trustable window (in case some data arrives just afterwards) - * may be as short as 1usec or so at 4Mbps. - */ - fifocnt = inw(ndev->base_addr+VLSI_PIO_RCVBCNT) & RCVBCNT_MASK; - irq->ifr_receiving = (fifocnt!=0) ? 1 : 0; - break; - default: - net_warn_ratelimited("%s: notsupp - cmd=%04x\n", - __func__, cmd); - ret = -EOPNOTSUPP; - } - - return ret; -} - -/********************************************************/ - -static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) -{ - struct net_device *ndev = dev_instance; - vlsi_irda_dev_t *idev = netdev_priv(ndev); - unsigned iobase; - u8 irintr; - int boguscount = 5; - unsigned long flags; - int handled = 0; - - iobase = ndev->base_addr; - spin_lock_irqsave(&idev->lock,flags); - do { - irintr = inb(iobase+VLSI_PIO_IRINTR); - mb(); - outb(irintr, iobase+VLSI_PIO_IRINTR); /* acknowledge asap */ - - if (!(irintr&=IRINTR_INT_MASK)) /* not our INT - probably shared */ - break; - - handled = 1; - - if (unlikely(!(irintr & ~IRINTR_ACTIVITY))) - break; /* nothing todo if only activity */ - - if (irintr&IRINTR_RPKTINT) - vlsi_rx_interrupt(ndev); - - if (irintr&IRINTR_TPKTINT) - vlsi_tx_interrupt(ndev); - - } while (--boguscount > 0); - spin_unlock_irqrestore(&idev->lock,flags); - - if (boguscount <= 0) - net_info_ratelimited("%s: too much work in interrupt!\n", - __func__); - return IRQ_RETVAL(handled); -} - -/********************************************************/ - -static int vlsi_open(struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - int err = -EAGAIN; - char hwname[32]; - - if (pci_request_regions(idev->pdev, drivername)) { - net_warn_ratelimited("%s: io resource busy\n", __func__); - goto errout; - } - ndev->base_addr = pci_resource_start(idev->pdev,0); - ndev->irq = idev->pdev->irq; - - /* under some rare occasions the chip apparently comes up with - * IRQ's pending. We better w/c pending IRQ and disable them all - */ - - outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR); - - if (request_irq(ndev->irq, vlsi_interrupt, IRQF_SHARED, - drivername, ndev)) { - net_warn_ratelimited("%s: couldn't get IRQ: %d\n", - __func__, ndev->irq); - goto errout_io; - } - - if ((err = vlsi_create_hwif(idev)) != 0) - goto errout_irq; - - sprintf(hwname, "VLSI-FIR @ 0x%04x", (unsigned)ndev->base_addr); - idev->irlap = irlap_open(ndev,&idev->qos,hwname); - if (!idev->irlap) - goto errout_free_ring; - - idev->last_rx = ktime_get(); /* first mtt may start from now on */ - - idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */ - - if ((err = vlsi_start_hw(idev)) != 0) - goto errout_close_irlap; - - netif_start_queue(ndev); - - net_info_ratelimited("%s: device %s operational\n", - __func__, ndev->name); - - return 0; - -errout_close_irlap: - irlap_close(idev->irlap); -errout_free_ring: - vlsi_destroy_hwif(idev); -errout_irq: - free_irq(ndev->irq,ndev); -errout_io: - pci_release_regions(idev->pdev); -errout: - return err; -} - -static int vlsi_close(struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - - netif_stop_queue(ndev); - - if (idev->irlap) - irlap_close(idev->irlap); - idev->irlap = NULL; - - vlsi_stop_hw(idev); - - vlsi_destroy_hwif(idev); - - free_irq(ndev->irq,ndev); - - pci_release_regions(idev->pdev); - - net_info_ratelimited("%s: device %s stopped\n", __func__, ndev->name); - - return 0; -} - -static const struct net_device_ops vlsi_netdev_ops = { - .ndo_open = vlsi_open, - .ndo_stop = vlsi_close, - .ndo_start_xmit = vlsi_hard_start_xmit, - .ndo_do_ioctl = vlsi_ioctl, - .ndo_tx_timeout = vlsi_tx_timeout, -}; - -static int vlsi_irda_init(struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - struct pci_dev *pdev = idev->pdev; - - ndev->irq = pdev->irq; - ndev->base_addr = pci_resource_start(pdev,0); - - /* PCI busmastering - * see include file for details why we need these 2 masks, in this order! - */ - - if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) || - pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) { - net_err_ratelimited("%s: aborting due to PCI BM-DMA address limitations\n", - __func__); - return -1; - } - - irda_init_max_qos_capabilies(&idev->qos); - - /* the VLSI82C147 does not support 576000! */ - - idev->qos.baud_rate.bits = IR_2400 | IR_9600 - | IR_19200 | IR_38400 | IR_57600 | IR_115200 - | IR_1152000 | (IR_4000000 << 8); - - idev->qos.min_turn_time.bits = qos_mtt_bits; - - irda_qos_bits_to_value(&idev->qos); - - /* currently no public media definitions for IrDA */ - - ndev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA; - ndev->if_port = IF_PORT_UNKNOWN; - - ndev->netdev_ops = &vlsi_netdev_ops; - ndev->watchdog_timeo = 500*HZ/1000; /* max. allowed turn time for IrLAP */ - - SET_NETDEV_DEV(ndev, &pdev->dev); - - return 0; -} - -/**************************************************************/ - -static int -vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct net_device *ndev; - vlsi_irda_dev_t *idev; - - if (pci_enable_device(pdev)) - goto out; - else - pdev->current_state = 0; /* hw must be running now */ - - net_info_ratelimited("%s: IrDA PCI controller %s detected\n", - drivername, pci_name(pdev)); - - if ( !pci_resource_start(pdev,0) || - !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { - net_err_ratelimited("%s: bar 0 invalid", __func__); - goto out_disable; - } - - ndev = alloc_irdadev(sizeof(*idev)); - if (ndev==NULL) { - net_err_ratelimited("%s: Unable to allocate device memory.\n", - __func__); - goto out_disable; - } - - idev = netdev_priv(ndev); - - spin_lock_init(&idev->lock); - mutex_init(&idev->mtx); - mutex_lock(&idev->mtx); - idev->pdev = pdev; - - if (vlsi_irda_init(ndev) < 0) - goto out_freedev; - - if (register_netdev(ndev) < 0) { - net_err_ratelimited("%s: register_netdev failed\n", __func__); - goto out_freedev; - } - - if (vlsi_proc_root != NULL) { - struct proc_dir_entry *ent; - - ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO, - vlsi_proc_root, VLSI_PROC_FOPS, ndev); - if (!ent) { - net_warn_ratelimited("%s: failed to create proc entry\n", - __func__); - } else { - proc_set_size(ent, 0); - } - idev->proc_entry = ent; - } - net_info_ratelimited("%s: registered device %s\n", - drivername, ndev->name); - - pci_set_drvdata(pdev, ndev); - mutex_unlock(&idev->mtx); - - return 0; - -out_freedev: - mutex_unlock(&idev->mtx); - free_netdev(ndev); -out_disable: - pci_disable_device(pdev); -out: - return -ENODEV; -} - -static void vlsi_irda_remove(struct pci_dev *pdev) -{ - struct net_device *ndev = pci_get_drvdata(pdev); - vlsi_irda_dev_t *idev; - - if (!ndev) { - net_err_ratelimited("%s: lost netdevice?\n", drivername); - return; - } - - unregister_netdev(ndev); - - idev = netdev_priv(ndev); - mutex_lock(&idev->mtx); - if (idev->proc_entry) { - remove_proc_entry(ndev->name, vlsi_proc_root); - idev->proc_entry = NULL; - } - mutex_unlock(&idev->mtx); - - free_netdev(ndev); - - net_info_ratelimited("%s: %s removed\n", drivername, pci_name(pdev)); -} - -#ifdef CONFIG_PM - -/* The Controller doesn't provide PCI PM capabilities as defined by PCI specs. - * Some of the Linux PCI-PM code however depends on this, for example in - * pci_set_power_state(). So we have to take care to perform the required - * operations on our own (particularly reflecting the pdev->current_state) - * otherwise we might get cheated by pci-pm. - */ - - -static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *ndev = pci_get_drvdata(pdev); - vlsi_irda_dev_t *idev; - - if (!ndev) { - net_err_ratelimited("%s - %s: no netdevice\n", - __func__, pci_name(pdev)); - return 0; - } - idev = netdev_priv(ndev); - mutex_lock(&idev->mtx); - if (pdev->current_state != 0) { /* already suspended */ - if (state.event > pdev->current_state) { /* simply go deeper */ - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - pdev->current_state = state.event; - } - else - net_err_ratelimited("%s - %s: invalid suspend request %u -> %u\n", - __func__, pci_name(pdev), - pdev->current_state, state.event); - mutex_unlock(&idev->mtx); - return 0; - } - - if (netif_running(ndev)) { - netif_device_detach(ndev); - vlsi_stop_hw(idev); - pci_save_state(pdev); - if (!idev->new_baud) - /* remember speed settings to restore on resume */ - idev->new_baud = idev->baud; - } - - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - pdev->current_state = state.event; - idev->resume_ok = 1; - mutex_unlock(&idev->mtx); - return 0; -} - -static int vlsi_irda_resume(struct pci_dev *pdev) -{ - struct net_device *ndev = pci_get_drvdata(pdev); - vlsi_irda_dev_t *idev; - - if (!ndev) { - net_err_ratelimited("%s - %s: no netdevice\n", - __func__, pci_name(pdev)); - return 0; - } - idev = netdev_priv(ndev); - mutex_lock(&idev->mtx); - if (pdev->current_state == 0) { - mutex_unlock(&idev->mtx); - net_warn_ratelimited("%s - %s: already resumed\n", - __func__, pci_name(pdev)); - return 0; - } - - pci_set_power_state(pdev, PCI_D0); - pdev->current_state = PM_EVENT_ON; - - if (!idev->resume_ok) { - /* should be obsolete now - but used to happen due to: - * - pci layer initially setting pdev->current_state = 4 (unknown) - * - pci layer did not walk the save_state-tree (might be APM problem) - * so we could not refuse to suspend from undefined state - * - vlsi_irda_suspend detected invalid state and refused to save - * configuration for resume - but was too late to stop suspending - * - vlsi_irda_resume got screwed when trying to resume from garbage - * - * now we explicitly set pdev->current_state = 0 after enabling the - * device and independently resume_ok should catch any garbage config. - */ - net_warn_ratelimited("%s - hm, nothing to resume?\n", __func__); - mutex_unlock(&idev->mtx); - return 0; - } - - if (netif_running(ndev)) { - pci_restore_state(pdev); - vlsi_start_hw(idev); - netif_device_attach(ndev); - } - idev->resume_ok = 0; - mutex_unlock(&idev->mtx); - return 0; -} - -#endif /* CONFIG_PM */ - -/*********************************************************/ - -static struct pci_driver vlsi_irda_driver = { - .name = drivername, - .id_table = vlsi_irda_table, - .probe = vlsi_irda_probe, - .remove = vlsi_irda_remove, -#ifdef CONFIG_PM - .suspend = vlsi_irda_suspend, - .resume = vlsi_irda_resume, -#endif -}; - -#define PROC_DIR ("driver/" DRIVER_NAME) - -static int __init vlsi_mod_init(void) -{ - int i, ret; - - if (clksrc < 0 || clksrc > 3) { - net_err_ratelimited("%s: invalid clksrc=%d\n", - drivername, clksrc); - return -1; - } - - for (i = 0; i < 2; i++) { - switch(ringsize[i]) { - case 4: - case 8: - case 16: - case 32: - case 64: - break; - default: - net_warn_ratelimited("%s: invalid %s ringsize %d, using default=8\n", - drivername, - i ? "rx" : "tx", - ringsize[i]); - ringsize[i] = 8; - break; - } - } - - sirpulse = !!sirpulse; - - /* proc_mkdir returns NULL if !CONFIG_PROC_FS. - * Failure to create the procfs entry is handled like running - * without procfs - it's not required for the driver to work. - */ - vlsi_proc_root = proc_mkdir(PROC_DIR, NULL); - - ret = pci_register_driver(&vlsi_irda_driver); - - if (ret && vlsi_proc_root) - remove_proc_entry(PROC_DIR, NULL); - return ret; - -} - -static void __exit vlsi_mod_exit(void) -{ - pci_unregister_driver(&vlsi_irda_driver); - if (vlsi_proc_root) - remove_proc_entry(PROC_DIR, NULL); -} - -module_init(vlsi_mod_init); -module_exit(vlsi_mod_exit); diff --git a/drivers/staging/irda/drivers/vlsi_ir.h b/drivers/staging/irda/drivers/vlsi_ir.h deleted file mode 100644 index f9db2ce4c5c6..000000000000 --- a/drivers/staging/irda/drivers/vlsi_ir.h +++ /dev/null @@ -1,757 +0,0 @@ - -/********************************************************************* - * - * vlsi_ir.h: VLSI82C147 PCI IrDA controller driver for Linux - * - * Version: 0.5 - * - * Copyright (c) 2001-2003 Martin Diehl - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRDA_VLSI_FIR_H -#define IRDA_VLSI_FIR_H - -/* ================================================================ - * compatibility stuff - */ - -/* definitions not present in pci_ids.h */ - -#ifndef PCI_CLASS_WIRELESS_IRDA -#define PCI_CLASS_WIRELESS_IRDA 0x0d00 -#endif - -#ifndef PCI_CLASS_SUBCLASS_MASK -#define PCI_CLASS_SUBCLASS_MASK 0xffff -#endif - -/* ================================================================ */ - -/* non-standard PCI registers */ - -enum vlsi_pci_regs { - VLSI_PCI_CLKCTL = 0x40, /* chip clock input control */ - VLSI_PCI_MSTRPAGE = 0x41, /* addr [31:24] for all busmaster cycles */ - VLSI_PCI_IRMISC = 0x42 /* mainly legacy UART related */ -}; - -/* ------------------------------------------ */ - -/* VLSI_PCI_CLKCTL: Clock Control Register (u8, rw) */ - -/* Three possible clock sources: either on-chip 48MHz PLL or - * external clock applied to EXTCLK pin. External clock may - * be either 48MHz or 40MHz, which is indicated by XCKSEL. - * CLKSTP controls whether the selected clock source gets - * connected to the IrDA block. - * - * On my HP OB-800 the BIOS sets external 40MHz clock as source - * when IrDA enabled and I've never detected any PLL lock success. - * Apparently the 14.3...MHz OSC input required for the PLL to work - * is not connected and the 40MHz EXTCLK is provided externally. - * At least this is what makes the driver working for me. - */ - -enum vlsi_pci_clkctl { - - /* PLL control */ - - CLKCTL_PD_INV = 0x04, /* PD#: inverted power down signal, - * i.e. PLL is powered, if PD_INV set */ - CLKCTL_LOCK = 0x40, /* (ro) set, if PLL is locked */ - - /* clock source selection */ - - CLKCTL_EXTCLK = 0x20, /* set to select external clock input, not PLL */ - CLKCTL_XCKSEL = 0x10, /* set to indicate EXTCLK is 40MHz, not 48MHz */ - - /* IrDA block control */ - - CLKCTL_CLKSTP = 0x80, /* set to disconnect from selected clock source */ - CLKCTL_WAKE = 0x08 /* set to enable wakeup feature: whenever IR activity - * is detected, PD_INV gets set(?) and CLKSTP cleared */ -}; - -/* ------------------------------------------ */ - -/* VLSI_PCI_MSTRPAGE: Master Page Register (u8, rw) and busmastering stuff */ - -#define DMA_MASK_USED_BY_HW 0xffffffff -#define DMA_MASK_MSTRPAGE 0x00ffffff -#define MSTRPAGE_VALUE (DMA_MASK_MSTRPAGE >> 24) - - /* PCI busmastering is somewhat special for this guy - in short: - * - * We select to operate using fixed MSTRPAGE=0, use ISA DMA - * address restrictions to make the PCI BM api aware of this, - * but ensure the hardware is dealing with real 32bit access. - * - * In detail: - * The chip executes normal 32bit busmaster cycles, i.e. - * drives all 32 address lines. These addresses however are - * composed of [0:23] taken from various busaddr-pointers - * and [24:31] taken from the MSTRPAGE register in the VLSI82C147 - * config space. Therefore _all_ busmastering must be - * targeted to/from one single 16MB (busaddr-) superpage! - * The point is to make sure all the allocations for memory - * locations with busmaster access (ring descriptors, buffers) - * are indeed bus-mappable to the same 16MB range (for x86 this - * means they must reside in the same 16MB physical memory address - * range). The only constraint we have which supports "several objects - * mappable to common 16MB range" paradigma, is the old ISA DMA - * restriction to the first 16MB of physical address range. - * Hence the approach here is to enable PCI busmaster support using - * the correct 32bit dma-mask used by the chip. Afterwards the device's - * dma-mask gets restricted to 24bit, which must be honoured somehow by - * all allocations for memory areas to be exposed to the chip ... - * - * Note: - * Don't be surprised to get "Setting latency timer..." messages every - * time when PCI busmastering is enabled for the chip. - * The chip has its PCI latency timer RO fixed at 0 - which is not a - * problem here, because it is never requesting _burst_ transactions. - */ - -/* ------------------------------------------ */ - -/* VLSI_PCIIRMISC: IR Miscellaneous Register (u8, rw) */ - -/* legacy UART emulation - not used by this driver - would require: - * (see below for some register-value definitions) - * - * - IRMISC_UARTEN must be set to enable UART address decoding - * - IRMISC_UARTSEL configured - * - IRCFG_MASTER must be cleared - * - IRCFG_SIR must be set - * - IRENABLE_PHYANDCLOCK must be asserted 0->1 (and hence IRENABLE_SIR_ON) - */ - -enum vlsi_pci_irmisc { - - /* IR transceiver control */ - - IRMISC_IRRAIL = 0x40, /* (ro?) IR rail power indication (and control?) - * 0=3.3V / 1=5V. Probably set during power-on? - * unclear - not touched by driver */ - IRMISC_IRPD = 0x08, /* transceiver power down, if set */ - - /* legacy UART control */ - - IRMISC_UARTTST = 0x80, /* UART test mode - "always write 0" */ - IRMISC_UARTEN = 0x04, /* enable UART address decoding */ - - /* bits [1:0] IRMISC_UARTSEL to select legacy UART address */ - - IRMISC_UARTSEL_3f8 = 0x00, - IRMISC_UARTSEL_2f8 = 0x01, - IRMISC_UARTSEL_3e8 = 0x02, - IRMISC_UARTSEL_2e8 = 0x03 -}; - -/* ================================================================ */ - -/* registers mapped to 32 byte PCI IO space */ - -/* note: better access all registers at the indicated u8/u16 size - * although some of them contain only 1 byte of information. - * some of them (particaluarly PROMPT and IRCFG) ignore - * access when using the wrong addressing mode! - */ - -enum vlsi_pio_regs { - VLSI_PIO_IRINTR = 0x00, /* interrupt enable/request (u8, rw) */ - VLSI_PIO_RINGPTR = 0x02, /* rx/tx ring pointer (u16, ro) */ - VLSI_PIO_RINGBASE = 0x04, /* [23:10] of ring address (u16, rw) */ - VLSI_PIO_RINGSIZE = 0x06, /* rx/tx ring size (u16, rw) */ - VLSI_PIO_PROMPT = 0x08, /* triggers ring processing (u16, wo) */ - /* 0x0a-0x0f: reserved / duplicated UART regs */ - VLSI_PIO_IRCFG = 0x10, /* configuration select (u16, rw) */ - VLSI_PIO_SIRFLAG = 0x12, /* BOF/EOF for filtered SIR (u16, ro) */ - VLSI_PIO_IRENABLE = 0x14, /* enable and status register (u16, rw/ro) */ - VLSI_PIO_PHYCTL = 0x16, /* physical layer current status (u16, ro) */ - VLSI_PIO_NPHYCTL = 0x18, /* next physical layer select (u16, rw) */ - VLSI_PIO_MAXPKT = 0x1a, /* [11:0] max len for packet receive (u16, rw) */ - VLSI_PIO_RCVBCNT = 0x1c /* current receive-FIFO byte count (u16, ro) */ - /* 0x1e-0x1f: reserved / duplicated UART regs */ -}; - -/* ------------------------------------------ */ - -/* VLSI_PIO_IRINTR: Interrupt Register (u8, rw) */ - -/* enable-bits: - * 1 = enable / 0 = disable - * interrupt condition bits: - * set according to corresponding interrupt source - * (regardless of the state of the enable bits) - * enable bit status indicates whether interrupt gets raised - * write-to-clear - * note: RPKTINT and TPKTINT behave different in legacy UART mode (which we don't use :-) - */ - -enum vlsi_pio_irintr { - IRINTR_ACTEN = 0x80, /* activity interrupt enable */ - IRINTR_ACTIVITY = 0x40, /* activity monitor (traffic detected) */ - IRINTR_RPKTEN = 0x20, /* receive packet interrupt enable*/ - IRINTR_RPKTINT = 0x10, /* rx-packet transferred from fifo to memory finished */ - IRINTR_TPKTEN = 0x08, /* transmit packet interrupt enable */ - IRINTR_TPKTINT = 0x04, /* last bit of tx-packet+crc shifted to ir-pulser */ - IRINTR_OE_EN = 0x02, /* UART rx fifo overrun error interrupt enable */ - IRINTR_OE_INT = 0x01 /* UART rx fifo overrun error (read LSR to clear) */ -}; - -/* we use this mask to check whether the (shared PCI) interrupt is ours */ - -#define IRINTR_INT_MASK (IRINTR_ACTIVITY|IRINTR_RPKTINT|IRINTR_TPKTINT) - -/* ------------------------------------------ */ - -/* VLSI_PIO_RINGPTR: Ring Pointer Read-Back Register (u16, ro) */ - -/* _both_ ring pointers are indices relative to the _entire_ rx,tx-ring! - * i.e. the referenced descriptor is located - * at RINGBASE + PTR * sizeof(descr) for rx and tx - * therefore, the tx-pointer has offset MAX_RING_DESCR - */ - -#define MAX_RING_DESCR 64 /* tx, rx rings may contain up to 64 descr each */ - -#define RINGPTR_RX_MASK (MAX_RING_DESCR-1) -#define RINGPTR_TX_MASK ((MAX_RING_DESCR-1)<<8) - -#define RINGPTR_GET_RX(p) ((p)&RINGPTR_RX_MASK) -#define RINGPTR_GET_TX(p) (((p)&RINGPTR_TX_MASK)>>8) - -/* ------------------------------------------ */ - -/* VLSI_PIO_RINGBASE: Ring Pointer Base Address Register (u16, ro) */ - -/* Contains [23:10] part of the ring base (bus-) address - * which must be 1k-alinged. [31:24] is taken from - * VLSI_PCI_MSTRPAGE above. - * The controller initiates non-burst PCI BM cycles to - * fetch and update the descriptors in the ring. - * Once fetched, the descriptor remains cached onchip - * until it gets closed and updated due to the ring - * processing state machine. - * The entire ring area is split in rx and tx areas with each - * area consisting of 64 descriptors of 8 bytes each. - * The rx(tx) ring is located at ringbase+0 (ringbase+64*8). - */ - -#define BUS_TO_RINGBASE(p) (((p)>>10)&0x3fff) - -/* ------------------------------------------ */ - -/* VLSI_PIO_RINGSIZE: Ring Size Register (u16, rw) */ - -/* bit mask to indicate the ring size to be used for rx and tx. - * possible values encoded bits - * 4 0000 - * 8 0001 - * 16 0011 - * 32 0111 - * 64 1111 - * located at [15:12] for tx and [11:8] for rx ([7:0] unused) - * - * note: probably a good idea to have IRCFG_MSTR cleared when writing - * this so the state machines are stopped and the RINGPTR is reset! - */ - -#define SIZE_TO_BITS(num) ((((num)-1)>>2)&0x0f) -#define TX_RX_TO_RINGSIZE(tx,rx) ((SIZE_TO_BITS(tx)<<12)|(SIZE_TO_BITS(rx)<<8)) -#define RINGSIZE_TO_RXSIZE(rs) ((((rs)&0x0f00)>>6)+4) -#define RINGSIZE_TO_TXSIZE(rs) ((((rs)&0xf000)>>10)+4) - - -/* ------------------------------------------ */ - -/* VLSI_PIO_PROMPT: Ring Prompting Register (u16, write-to-start) */ - -/* writing any value kicks the ring processing state machines - * for both tx, rx rings as follows: - * - active rings (currently owning an active descriptor) - * ignore the prompt and continue - * - idle rings fetch the next descr from the ring and start - * their processing - */ - -/* ------------------------------------------ */ - -/* VLSI_PIO_IRCFG: IR Config Register (u16, rw) */ - -/* notes: - * - not more than one SIR/MIR/FIR bit must be set at any time - * - SIR, MIR, FIR and CRC16 select the configuration which will - * be applied on next 0->1 transition of IRENABLE_PHYANDCLOCK (see below). - * - besides allowing the PCI interface to execute busmaster cycles - * and therefore the ring SM to operate, the MSTR bit has side-effects: - * when MSTR is cleared, the RINGPTR's get reset and the legacy UART mode - * (in contrast to busmaster access mode) gets enabled. - * - clearing ENRX or setting ENTX while data is received may stall the - * receive fifo until ENRX reenabled _and_ another packet arrives - * - SIRFILT means the chip performs the required unwrapping of hardware - * headers (XBOF's, BOF/EOF) and un-escaping in the _receive_ direction. - * Only the resulting IrLAP payload is copied to the receive buffers - - * but with the 16bit FCS still encluded. Question remains, whether it - * was already checked or we should do it before passing the packet to IrLAP? - */ - -enum vlsi_pio_ircfg { - IRCFG_LOOP = 0x4000, /* enable loopback test mode */ - IRCFG_ENTX = 0x1000, /* transmit enable */ - IRCFG_ENRX = 0x0800, /* receive enable */ - IRCFG_MSTR = 0x0400, /* master enable */ - IRCFG_RXANY = 0x0200, /* receive any packet */ - IRCFG_CRC16 = 0x0080, /* 16bit (not 32bit) CRC select for MIR/FIR */ - IRCFG_FIR = 0x0040, /* FIR 4PPM encoding mode enable */ - IRCFG_MIR = 0x0020, /* MIR HDLC encoding mode enable */ - IRCFG_SIR = 0x0010, /* SIR encoding mode enable */ - IRCFG_SIRFILT = 0x0008, /* enable SIR decode filter (receiver unwrapping) */ - IRCFG_SIRTEST = 0x0004, /* allow SIR decode filter when not in SIR mode */ - IRCFG_TXPOL = 0x0002, /* invert tx polarity when set */ - IRCFG_RXPOL = 0x0001 /* invert rx polarity when set */ -}; - -/* ------------------------------------------ */ - -/* VLSI_PIO_SIRFLAG: SIR Flag Register (u16, ro) */ - -/* register contains hardcoded BOF=0xc0 at [7:0] and EOF=0xc1 at [15:8] - * which is used for unwrapping received frames in SIR decode-filter mode - */ - -/* ------------------------------------------ */ - -/* VLSI_PIO_IRENABLE: IR Enable Register (u16, rw/ro) */ - -/* notes: - * - IREN acts as gate for latching the configured IR mode information - * from IRCFG and IRPHYCTL when IREN=reset and applying them when - * IREN gets set afterwards. - * - ENTXST reflects IRCFG_ENTX - * - ENRXST = IRCFG_ENRX && (!IRCFG_ENTX || IRCFG_LOOP) - */ - -enum vlsi_pio_irenable { - IRENABLE_PHYANDCLOCK = 0x8000, /* enable IR phy and gate the mode config (rw) */ - IRENABLE_CFGER = 0x4000, /* mode configuration error (ro) */ - IRENABLE_FIR_ON = 0x2000, /* FIR on status (ro) */ - IRENABLE_MIR_ON = 0x1000, /* MIR on status (ro) */ - IRENABLE_SIR_ON = 0x0800, /* SIR on status (ro) */ - IRENABLE_ENTXST = 0x0400, /* transmit enable status (ro) */ - IRENABLE_ENRXST = 0x0200, /* Receive enable status (ro) */ - IRENABLE_CRC16_ON = 0x0100 /* 16bit (not 32bit) CRC enabled status (ro) */ -}; - -#define IRENABLE_MASK 0xff00 /* Read mask */ - -/* ------------------------------------------ */ - -/* VLSI_PIO_PHYCTL: IR Physical Layer Current Control Register (u16, ro) */ - -/* read-back of the currently applied physical layer status. - * applied from VLSI_PIO_NPHYCTL at rising edge of IRENABLE_PHYANDCLOCK - * contents identical to VLSI_PIO_NPHYCTL (see below) - */ - -/* ------------------------------------------ */ - -/* VLSI_PIO_NPHYCTL: IR Physical Layer Next Control Register (u16, rw) */ - -/* latched during IRENABLE_PHYANDCLOCK=0 and applied at 0-1 transition - * - * consists of BAUD[15:10], PLSWID[9:5] and PREAMB[4:0] bits defined as follows: - * - * SIR-mode: BAUD = (115.2kHz / baudrate) - 1 - * PLSWID = (pulsetime * freq / (BAUD+1)) - 1 - * where pulsetime is the requested IrPHY pulse width - * and freq is 8(16)MHz for 40(48)MHz primary input clock - * PREAMB: don't care for SIR - * - * The nominal SIR pulse width is 3/16 bit time so we have PLSWID=12 - * fixed for all SIR speeds at 40MHz input clock (PLSWID=24 at 48MHz). - * IrPHY also allows shorter pulses down to the nominal pulse duration - * at 115.2kbaud (minus some tolerance) which is 1.41 usec. - * Using the expression PLSWID = 12/(BAUD+1)-1 (multiplied by two for 48MHz) - * we get the minimum acceptable PLSWID values according to the VLSI - * specification, which provides 1.5 usec pulse width for all speeds (except - * for 2.4kbaud getting 6usec). This is fine with IrPHY v1.3 specs and - * reduces the transceiver power which drains the battery. At 9.6kbaud for - * example this amounts to more than 90% battery power saving! - * - * MIR-mode: BAUD = 0 - * PLSWID = 9(10) for 40(48) MHz input clock - * to get nominal MIR pulse width - * PREAMB = 1 - * - * FIR-mode: BAUD = 0 - * PLSWID: don't care - * PREAMB = 15 - */ - -#define PHYCTL_BAUD_SHIFT 10 -#define PHYCTL_BAUD_MASK 0xfc00 -#define PHYCTL_PLSWID_SHIFT 5 -#define PHYCTL_PLSWID_MASK 0x03e0 -#define PHYCTL_PREAMB_SHIFT 0 -#define PHYCTL_PREAMB_MASK 0x001f - -#define PHYCTL_TO_BAUD(bwp) (((bwp)&PHYCTL_BAUD_MASK)>>PHYCTL_BAUD_SHIFT) -#define PHYCTL_TO_PLSWID(bwp) (((bwp)&PHYCTL_PLSWID_MASK)>>PHYCTL_PLSWID_SHIFT) -#define PHYCTL_TO_PREAMB(bwp) (((bwp)&PHYCTL_PREAMB_MASK)>>PHYCTL_PREAMB_SHIFT) - -#define BWP_TO_PHYCTL(b,w,p) ((((b)<<PHYCTL_BAUD_SHIFT)&PHYCTL_BAUD_MASK) \ - | (((w)<<PHYCTL_PLSWID_SHIFT)&PHYCTL_PLSWID_MASK) \ - | (((p)<<PHYCTL_PREAMB_SHIFT)&PHYCTL_PREAMB_MASK)) - -#define BAUD_BITS(br) ((115200/(br))-1) - -static inline unsigned -calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect) -{ - unsigned tmp; - - if (widthselect) /* nominal 3/16 puls width */ - return (clockselect) ? 12 : 24; - - tmp = ((clockselect) ? 12 : 24) / (BAUD_BITS(baudrate)+1); - - /* intermediate result of integer division needed here */ - - return (tmp>0) ? (tmp-1) : 0; -} - -#define PHYCTL_SIR(br,ws,cs) BWP_TO_PHYCTL(BAUD_BITS(br),calc_width_bits((br),(ws),(cs)),0) -#define PHYCTL_MIR(cs) BWP_TO_PHYCTL(0,((cs)?9:10),1) -#define PHYCTL_FIR BWP_TO_PHYCTL(0,0,15) - -/* quite ugly, I know. But implementing these calculations here avoids - * having magic numbers in the code and allows some playing with pulsewidths - * without risk to violate the standards. - * FWIW, here is the table for reference: - * - * baudrate BAUD min-PLSWID nom-PLSWID PREAMB - * 2400 47 0(0) 12(24) 0 - * 9600 11 0(0) 12(24) 0 - * 19200 5 1(2) 12(24) 0 - * 38400 2 3(6) 12(24) 0 - * 57600 1 5(10) 12(24) 0 - * 115200 0 11(22) 12(24) 0 - * MIR 0 - 9(10) 1 - * FIR 0 - 0 15 - * - * note: x(y) means x-value for 40MHz / y-value for 48MHz primary input clock - */ - -/* ------------------------------------------ */ - - -/* VLSI_PIO_MAXPKT: Maximum Packet Length register (u16, rw) */ - -/* maximum acceptable length for received packets */ - -/* hw imposed limitation - register uses only [11:0] */ -#define MAX_PACKET_LENGTH 0x0fff - -/* IrLAP I-field (apparently not defined elsewhere) */ -#define IRDA_MTU 2048 - -/* complete packet consists of A(1)+C(1)+I(<=IRDA_MTU) */ -#define IRLAP_SKB_ALLOCSIZE (1+1+IRDA_MTU) - -/* the buffers we use to exchange frames with the hardware need to be - * larger than IRLAP_SKB_ALLOCSIZE because we may have up to 4 bytes FCS - * appended and, in SIR mode, a lot of frame wrapping bytes. The worst - * case appears to be a SIR packet with I-size==IRDA_MTU and all bytes - * requiring to be escaped to provide transparency. Furthermore, the peer - * might ask for quite a number of additional XBOFs: - * up to 115+48 XBOFS 163 - * regular BOF 1 - * A-field 1 - * C-field 1 - * I-field, IRDA_MTU, all escaped 4096 - * FCS (16 bit at SIR, escaped) 4 - * EOF 1 - * AFAICS nothing in IrLAP guarantees A/C field not to need escaping - * (f.e. 0xc0/0xc1 - i.e. BOF/EOF - are legal values there) so in the - * worst case we have 4269 bytes total frame size. - * However, the VLSI uses 12 bits only for all buffer length values, - * which limits the maximum useable buffer size <= 4095. - * Note this is not a limitation in the receive case because we use - * the SIR filtering mode where the hw unwraps the frame and only the - * bare packet+fcs is stored into the buffer - in contrast to the SIR - * tx case where we have to pass frame-wrapped packets to the hw. - * If this would ever become an issue in real life, the only workaround - * I see would be using the legacy UART emulation in SIR mode. - */ - -#define XFER_BUF_SIZE MAX_PACKET_LENGTH - -/* ------------------------------------------ */ - -/* VLSI_PIO_RCVBCNT: Receive Byte Count Register (u16, ro) */ - -/* receive packet counter gets incremented on every non-filtered - * byte which was put in the receive fifo and reset for each - * new packet. Used to decide whether we are just in the middle - * of receiving - */ - -/* better apply the [11:0] mask when reading, as some docs say the - * reserved [15:12] would return 1 when reading - which is wrong AFAICS - */ -#define RCVBCNT_MASK 0x0fff - -/******************************************************************/ - -/* descriptors for rx/tx ring - * - * accessed by hardware - don't change! - * - * the descriptor is owned by hardware, when the ACTIVE status bit - * is set and nothing (besides reading status to test the bit) - * shall be done. The bit gets cleared by hw, when the descriptor - * gets closed. Premature reaping of descriptors owned be the chip - * can be achieved by disabling IRCFG_MSTR - * - * Attention: Writing addr overwrites status! - * - * ### FIXME: depends on endianess (but there ain't no non-i586 ob800 ;-) - */ - -struct ring_descr_hw { - volatile __le16 rd_count; /* tx/rx count [11:0] */ - __le16 reserved; - union { - __le32 addr; /* [23:0] of the buffer's busaddress */ - struct { - u8 addr_res[3]; - volatile u8 status; /* descriptor status */ - } __packed rd_s; - } __packed rd_u; -} __packed; - -#define rd_addr rd_u.addr -#define rd_status rd_u.rd_s.status - -/* ring descriptor status bits */ - -#define RD_ACTIVE 0x80 /* descriptor owned by hw (both TX,RX) */ - -/* TX ring descriptor status */ - -#define RD_TX_DISCRC 0x40 /* do not send CRC (for SIR) */ -#define RD_TX_BADCRC 0x20 /* force a bad CRC */ -#define RD_TX_PULSE 0x10 /* send indication pulse after this frame (MIR/FIR) */ -#define RD_TX_FRCEUND 0x08 /* force underrun */ -#define RD_TX_CLRENTX 0x04 /* clear ENTX after this frame */ -#define RD_TX_UNDRN 0x01 /* TX fifo underrun (probably PCI problem) */ - -/* RX ring descriptor status */ - -#define RD_RX_PHYERR 0x40 /* physical encoding error */ -#define RD_RX_CRCERR 0x20 /* CRC error (MIR/FIR) */ -#define RD_RX_LENGTH 0x10 /* frame exceeds buffer length */ -#define RD_RX_OVER 0x08 /* RX fifo overrun (probably PCI problem) */ -#define RD_RX_SIRBAD 0x04 /* EOF missing: BOF follows BOF (SIR, filtered) */ - -#define RD_RX_ERROR 0x7c /* any error in received frame */ - -/* the memory required to hold the 2 descriptor rings */ -#define HW_RING_AREA_SIZE (2 * MAX_RING_DESCR * sizeof(struct ring_descr_hw)) - -/******************************************************************/ - -/* sw-ring descriptors consists of a bus-mapped transfer buffer with - * associated skb and a pointer to the hw entry descriptor - */ - -struct ring_descr { - struct ring_descr_hw *hw; - struct sk_buff *skb; - void *buf; -}; - -/* wrappers for operations on hw-exposed ring descriptors - * access to the hw-part of the descriptors must use these. - */ - -static inline int rd_is_active(struct ring_descr *rd) -{ - return (rd->hw->rd_status & RD_ACTIVE) != 0; -} - -static inline void rd_activate(struct ring_descr *rd) -{ - rd->hw->rd_status |= RD_ACTIVE; -} - -static inline void rd_set_status(struct ring_descr *rd, u8 s) -{ - rd->hw->rd_status = s; /* may pass ownership to the hardware */ -} - -static inline void rd_set_addr_status(struct ring_descr *rd, dma_addr_t a, u8 s) -{ - /* order is important for two reasons: - * - overlayed: writing addr overwrites status - * - we want to write status last so we have valid address in - * case status has RD_ACTIVE set - */ - - if ((a & ~DMA_MASK_MSTRPAGE)>>24 != MSTRPAGE_VALUE) { - net_err_ratelimited("%s: pci busaddr inconsistency!\n", - __func__); - dump_stack(); - return; - } - - a &= DMA_MASK_MSTRPAGE; /* clear highbyte to make sure we won't write - * to status - just in case MSTRPAGE_VALUE!=0 - */ - rd->hw->rd_addr = cpu_to_le32(a); - wmb(); - rd_set_status(rd, s); /* may pass ownership to the hardware */ -} - -static inline void rd_set_count(struct ring_descr *rd, u16 c) -{ - rd->hw->rd_count = cpu_to_le16(c); -} - -static inline u8 rd_get_status(struct ring_descr *rd) -{ - return rd->hw->rd_status; -} - -static inline dma_addr_t rd_get_addr(struct ring_descr *rd) -{ - dma_addr_t a; - - a = le32_to_cpu(rd->hw->rd_addr); - return (a & DMA_MASK_MSTRPAGE) | (MSTRPAGE_VALUE << 24); -} - -static inline u16 rd_get_count(struct ring_descr *rd) -{ - return le16_to_cpu(rd->hw->rd_count); -} - -/******************************************************************/ - -/* sw descriptor rings for rx, tx: - * - * operations follow producer-consumer paradigm, with the hw - * in the middle doing the processing. - * ring size must be power of two. - * - * producer advances r->tail after inserting for processing - * consumer advances r->head after removing processed rd - * ring is empty if head==tail / full if (tail+1)==head - */ - -struct vlsi_ring { - struct pci_dev *pdev; - int dir; - unsigned len; - unsigned size; - unsigned mask; - atomic_t head, tail; - struct ring_descr *rd; -}; - -/* ring processing helpers */ - -static inline struct ring_descr *ring_last(struct vlsi_ring *r) -{ - int t; - - t = atomic_read(&r->tail) & r->mask; - return (((t+1) & r->mask) == (atomic_read(&r->head) & r->mask)) ? NULL : &r->rd[t]; -} - -static inline struct ring_descr *ring_put(struct vlsi_ring *r) -{ - atomic_inc(&r->tail); - return ring_last(r); -} - -static inline struct ring_descr *ring_first(struct vlsi_ring *r) -{ - int h; - - h = atomic_read(&r->head) & r->mask; - return (h == (atomic_read(&r->tail) & r->mask)) ? NULL : &r->rd[h]; -} - -static inline struct ring_descr *ring_get(struct vlsi_ring *r) -{ - atomic_inc(&r->head); - return ring_first(r); -} - -/******************************************************************/ - -/* our private compound VLSI-PCI-IRDA device information */ - -typedef struct vlsi_irda_dev { - struct pci_dev *pdev; - - struct irlap_cb *irlap; - - struct qos_info qos; - - unsigned mode; - int baud, new_baud; - - dma_addr_t busaddr; - void *virtaddr; - struct vlsi_ring *tx_ring, *rx_ring; - - ktime_t last_rx; - - spinlock_t lock; - struct mutex mtx; - - u8 resume_ok; - struct proc_dir_entry *proc_entry; - -} vlsi_irda_dev_t; - -/********************************************************/ - -/* the remapped error flags we use for returning from frame - * post-processing in vlsi_process_tx/rx() after it was completed - * by the hardware. These functions either return the >=0 number - * of transferred bytes in case of success or the negative (-) - * of the or'ed error flags. - */ - -#define VLSI_TX_DROP 0x0001 -#define VLSI_TX_FIFO 0x0002 - -#define VLSI_RX_DROP 0x0100 -#define VLSI_RX_OVER 0x0200 -#define VLSI_RX_LENGTH 0x0400 -#define VLSI_RX_FRAME 0x0800 -#define VLSI_RX_CRC 0x1000 - -/********************************************************/ - -#endif /* IRDA_VLSI_FIR_H */ - diff --git a/drivers/staging/irda/drivers/w83977af.h b/drivers/staging/irda/drivers/w83977af.h deleted file mode 100644 index 04476c2e9121..000000000000 --- a/drivers/staging/irda/drivers/w83977af.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef W83977AF_H -#define W83977AF_H - -#define W977_EFIO_BASE 0x370 -#define W977_EFIO2_BASE 0x3f0 -#define W977_DEVICE_IR 0x06 - - -/* - * Enter extended function mode - */ -static inline void w977_efm_enter(unsigned int efio) -{ - outb(0x87, efio); - outb(0x87, efio); -} - -/* - * Select a device to configure - */ - -static inline void w977_select_device(__u8 devnum, unsigned int efio) -{ - outb(0x07, efio); - outb(devnum, efio+1); -} - -/* - * Write a byte to a register - */ -static inline void w977_write_reg(__u8 reg, __u8 value, unsigned int efio) -{ - outb(reg, efio); - outb(value, efio+1); -} - -/* - * read a byte from a register - */ -static inline __u8 w977_read_reg(__u8 reg, unsigned int efio) -{ - outb(reg, efio); - return inb(efio+1); -} - -/* - * Exit extended function mode - */ -static inline void w977_efm_exit(unsigned int efio) -{ - outb(0xAA, efio); -} -#endif diff --git a/drivers/staging/irda/drivers/w83977af_ir.c b/drivers/staging/irda/drivers/w83977af_ir.c deleted file mode 100644 index 282b6c9ae05b..000000000000 --- a/drivers/staging/irda/drivers/w83977af_ir.c +++ /dev/null @@ -1,1285 +0,0 @@ -/********************************************************************* - * - * Filename: w83977af_ir.c - * Version: 1.0 - * Description: FIR driver for the Winbond W83977AF Super I/O chip - * Status: Experimental. - * Author: Paul VanderSpek - * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Fri Jan 28 12:10:59 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1998-1999 Rebel.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. - * - * Neither Paul VanderSpek nor Rebel.com admit liability nor provide - * warranty for any of this software. This material is provided "AS-IS" - * and at no charge. - * - * If you find bugs in this file, its very likely that the same bug - * will also be in pc87108.c since the implementations are quite - * similar. - * - * Notice that all functions that needs to access the chip in _any_ - * way, must save BSR register on entry, and restore it on exit. - * It is _very_ important to follow this policy! - * - * __u8 bank; - * - * bank = inb( iobase+BSR); - * - * do_your_stuff_here(); - * - * outb( bank, iobase+BSR); - * - ********************************************************************/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/rtnetlink.h> -#include <linux/dma-mapping.h> -#include <linux/gfp.h> - -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/irda_device.h> -#include "w83977af.h" -#include "w83977af_ir.h" - -#define CONFIG_USE_W977_PNP /* Currently needed */ -#define PIO_MAX_SPEED 115200 - -static char *driver_name = "w83977af_ir"; -static int qos_mtt_bits = 0x07; /* 1 ms or more */ - -#define CHIP_IO_EXTENT 8 - -static unsigned int io[] = { 0x180, ~0, ~0, ~0 }; -#ifdef CONFIG_ARCH_NETWINDER /* Adjust to NetWinder differences */ -static unsigned int irq[] = { 6, 0, 0, 0 }; -#else -static unsigned int irq[] = { 11, 0, 0, 0 }; -#endif -static unsigned int dma[] = { 1, 0, 0, 0 }; -static unsigned int efbase[] = { W977_EFIO_BASE, W977_EFIO2_BASE }; -static unsigned int efio = W977_EFIO_BASE; - -static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL}; - -/* Some prototypes */ -static int w83977af_open(int i, unsigned int iobase, unsigned int irq, - unsigned int dma); -static int w83977af_close(struct w83977af_ir *self); -static int w83977af_probe(int iobase, int irq, int dma); -static int w83977af_dma_receive(struct w83977af_ir *self); -static int w83977af_dma_receive_complete(struct w83977af_ir *self); -static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, - struct net_device *dev); -static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size); -static void w83977af_dma_write(struct w83977af_ir *self, int iobase); -static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed); -static int w83977af_is_receiving(struct w83977af_ir *self); - -static int w83977af_net_open(struct net_device *dev); -static int w83977af_net_close(struct net_device *dev); -static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); - -/* - * Function w83977af_init () - * - * Initialize chip. Just try to find out how many chips we are dealing with - * and where they are - */ -static int __init w83977af_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dev_self) && io[i] < 2000; i++) { - if (w83977af_open(i, io[i], irq[i], dma[i]) == 0) - return 0; - } - return -ENODEV; -} - -/* - * Function w83977af_cleanup () - * - * Close all configured chips - * - */ -static void __exit w83977af_cleanup(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dev_self); i++) { - if (dev_self[i]) - w83977af_close(dev_self[i]); - } -} - -static const struct net_device_ops w83977_netdev_ops = { - .ndo_open = w83977af_net_open, - .ndo_stop = w83977af_net_close, - .ndo_start_xmit = w83977af_hard_xmit, - .ndo_do_ioctl = w83977af_net_ioctl, -}; - -/* - * Function w83977af_open (iobase, irq) - * - * Open driver instance - * - */ -static int w83977af_open(int i, unsigned int iobase, unsigned int irq, - unsigned int dma) -{ - struct net_device *dev; - struct w83977af_ir *self; - int err; - - /* Lock the port that we need */ - if (!request_region(iobase, CHIP_IO_EXTENT, driver_name)) { - pr_debug("%s: can't get iobase of 0x%03x\n", - __func__, iobase); - return -ENODEV; - } - - if (w83977af_probe(iobase, irq, dma) == -1) { - err = -1; - goto err_out; - } - /* - * Allocate new instance of the driver - */ - dev = alloc_irdadev(sizeof(struct w83977af_ir)); - if (!dev) { - pr_err("IrDA: Can't allocate memory for IrDA control block!\n"); - err = -ENOMEM; - goto err_out; - } - - self = netdev_priv(dev); - spin_lock_init(&self->lock); - - /* Initialize IO */ - self->io.fir_base = iobase; - self->io.irq = irq; - self->io.fir_ext = CHIP_IO_EXTENT; - self->io.dma = dma; - self->io.fifo_size = 32; - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - /* The only value we must override it the baudrate */ - - /* FIXME: The HP HDLS-1100 does not support 1152000! */ - self->qos.baud_rate.bits = IR_9600 | IR_19200 | IR_38400 | IR_57600 | - IR_115200 | IR_576000 | IR_1152000 | (IR_4000000 << 8); - - /* The HP HDLS-1100 needs 1 ms according to the specs */ - self->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&self->qos); - - /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */ - self->rx_buff.truesize = 14384; - self->tx_buff.truesize = 4000; - - /* Allocate memory if needed */ - self->rx_buff.head = - dma_zalloc_coherent(NULL, self->rx_buff.truesize, - &self->rx_buff_dma, GFP_KERNEL); - if (!self->rx_buff.head) { - err = -ENOMEM; - goto err_out1; - } - - self->tx_buff.head = - dma_zalloc_coherent(NULL, self->tx_buff.truesize, - &self->tx_buff_dma, GFP_KERNEL); - if (!self->tx_buff.head) { - err = -ENOMEM; - goto err_out2; - } - - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->tx_buff.data = self->tx_buff.head; - self->rx_buff.data = self->rx_buff.head; - self->netdev = dev; - - dev->netdev_ops = &w83977_netdev_ops; - - err = register_netdev(dev); - if (err) { - net_err_ratelimited("%s:, register_netdevice() failed!\n", - __func__); - goto err_out3; - } - net_info_ratelimited("IrDA: Registered device %s\n", dev->name); - - /* Need to store self somewhere */ - dev_self[i] = self; - - return 0; -err_out3: - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); -err_out2: - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); -err_out1: - free_netdev(dev); -err_out: - release_region(iobase, CHIP_IO_EXTENT); - return err; -} - -/* - * Function w83977af_close (self) - * - * Close driver instance - * - */ -static int w83977af_close(struct w83977af_ir *self) -{ - int iobase; - - iobase = self->io.fir_base; - -#ifdef CONFIG_USE_W977_PNP - /* enter PnP configuration mode */ - w977_efm_enter(efio); - - w977_select_device(W977_DEVICE_IR, efio); - - /* Deactivate device */ - w977_write_reg(0x30, 0x00, efio); - - w977_efm_exit(efio); -#endif /* CONFIG_USE_W977_PNP */ - - /* Remove netdevice */ - unregister_netdev(self->netdev); - - /* Release the PORT that this driver is using */ - pr_debug("%s: Releasing Region %03x\n", __func__, self->io.fir_base); - release_region(self->io.fir_base, self->io.fir_ext); - - if (self->tx_buff.head) - dma_free_coherent(NULL, self->tx_buff.truesize, - self->tx_buff.head, self->tx_buff_dma); - - if (self->rx_buff.head) - dma_free_coherent(NULL, self->rx_buff.truesize, - self->rx_buff.head, self->rx_buff_dma); - - free_netdev(self->netdev); - - return 0; -} - -static int w83977af_probe(int iobase, int irq, int dma) -{ - int version; - int i; - - for (i = 0; i < 2; i++) { -#ifdef CONFIG_USE_W977_PNP - /* Enter PnP configuration mode */ - w977_efm_enter(efbase[i]); - - w977_select_device(W977_DEVICE_IR, efbase[i]); - - /* Configure PnP port, IRQ, and DMA channel */ - w977_write_reg(0x60, (iobase >> 8) & 0xff, efbase[i]); - w977_write_reg(0x61, (iobase) & 0xff, efbase[i]); - - w977_write_reg(0x70, irq, efbase[i]); -#ifdef CONFIG_ARCH_NETWINDER - /* Netwinder uses 1 higher than Linux */ - w977_write_reg(0x74, dma + 1, efbase[i]); -#else - w977_write_reg(0x74, dma, efbase[i]); -#endif /* CONFIG_ARCH_NETWINDER */ - w977_write_reg(0x75, 0x04, efbase[i]);/* Disable Tx DMA */ - - /* Set append hardware CRC, enable IR bank selection */ - w977_write_reg(0xf0, APEDCRC | ENBNKSEL, efbase[i]); - - /* Activate device */ - w977_write_reg(0x30, 0x01, efbase[i]); - - w977_efm_exit(efbase[i]); -#endif /* CONFIG_USE_W977_PNP */ - /* Disable Advanced mode */ - switch_bank(iobase, SET2); - outb(iobase + 2, 0x00); - - /* Turn on UART (global) interrupts */ - switch_bank(iobase, SET0); - outb(HCR_EN_IRQ, iobase + HCR); - - /* Switch to advanced mode */ - switch_bank(iobase, SET2); - outb(inb(iobase + ADCR1) | ADCR1_ADV_SL, iobase + ADCR1); - - /* Set default IR-mode */ - switch_bank(iobase, SET0); - outb(HCR_SIR, iobase + HCR); - - /* Read the Advanced IR ID */ - switch_bank(iobase, SET3); - version = inb(iobase + AUID); - - /* Should be 0x1? */ - if (0x10 == (version & 0xf0)) { - efio = efbase[i]; - - /* Set FIFO size to 32 */ - switch_bank(iobase, SET2); - outb(ADCR2_RXFS32 | ADCR2_TXFS32, iobase + ADCR2); - - /* Set FIFO threshold to TX17, RX16 */ - switch_bank(iobase, SET0); - outb(UFR_RXTL | UFR_TXTL | UFR_TXF_RST | UFR_RXF_RST | - UFR_EN_FIFO, iobase + UFR); - - /* Receiver frame length */ - switch_bank(iobase, SET4); - outb(2048 & 0xff, iobase + 6); - outb((2048 >> 8) & 0x1f, iobase + 7); - - /* - * Init HP HSDL-1100 transceiver. - * - * Set IRX_MSL since we have 2 * receive paths IRRX, - * and IRRXH. Clear IRSL0D since we want IRSL0 * to - * be a input pin used for IRRXH - * - * IRRX pin 37 connected to receiver - * IRTX pin 38 connected to transmitter - * FIRRX pin 39 connected to receiver (IRSL0) - * CIRRX pin 40 connected to pin 37 - */ - switch_bank(iobase, SET7); - outb(0x40, iobase + 7); - - net_info_ratelimited("W83977AF (IR) driver loaded. Version: 0x%02x\n", - version); - - return 0; - } else { - /* Try next extented function register address */ - pr_debug("%s: Wrong chip version\n", __func__); - } - } - return -1; -} - -static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) -{ - int ir_mode = HCR_SIR; - int iobase; - __u8 set; - - iobase = self->io.fir_base; - - /* Update accounting for new speed */ - self->io.speed = speed; - - /* Save current bank */ - set = inb(iobase + SSR); - - /* Disable interrupts */ - switch_bank(iobase, SET0); - outb(0, iobase + ICR); - - /* Select Set 2 */ - switch_bank(iobase, SET2); - outb(0x00, iobase + ABHL); - - switch (speed) { - case 9600: outb(0x0c, iobase + ABLL); break; - case 19200: outb(0x06, iobase + ABLL); break; - case 38400: outb(0x03, iobase + ABLL); break; - case 57600: outb(0x02, iobase + ABLL); break; - case 115200: outb(0x01, iobase + ABLL); break; - case 576000: - ir_mode = HCR_MIR_576; - pr_debug("%s: handling baud of 576000\n", __func__); - break; - case 1152000: - ir_mode = HCR_MIR_1152; - pr_debug("%s: handling baud of 1152000\n", __func__); - break; - case 4000000: - ir_mode = HCR_FIR; - pr_debug("%s: handling baud of 4000000\n", __func__); - break; - default: - ir_mode = HCR_FIR; - pr_debug("%s: unknown baud rate of %d\n", __func__, speed); - break; - } - - /* Set speed mode */ - switch_bank(iobase, SET0); - outb(ir_mode, iobase + HCR); - - /* set FIFO size to 32 */ - switch_bank(iobase, SET2); - outb(ADCR2_RXFS32 | ADCR2_TXFS32, iobase + ADCR2); - - /* set FIFO threshold to TX17, RX16 */ - switch_bank(iobase, SET0); - outb(0x00, iobase + UFR); /* Reset */ - outb(UFR_EN_FIFO, iobase + UFR); /* First we must enable FIFO */ - outb(0xa7, iobase + UFR); - - netif_wake_queue(self->netdev); - - /* Enable some interrupts so we can receive frames */ - switch_bank(iobase, SET0); - if (speed > PIO_MAX_SPEED) { - outb(ICR_EFSFI, iobase + ICR); - w83977af_dma_receive(self); - } else { - outb(ICR_ERBRI, iobase + ICR); - } - - /* Restore SSR */ - outb(set, iobase + SSR); -} - -/* - * Function w83977af_hard_xmit (skb, dev) - * - * Sets up a DMA transfer to send the current frame. - * - */ -static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct w83977af_ir *self; - __s32 speed; - int iobase; - __u8 set; - int mtt; - - self = netdev_priv(dev); - - iobase = self->io.fir_base; - - pr_debug("%s: %ld, skb->len=%d\n", __func__, jiffies, (int)skb->len); - - /* Lock transmit buffer */ - netif_stop_queue(dev); - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - /* Check for empty frame */ - if (!skb->len) { - w83977af_change_speed(self, speed); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - self->new_speed = speed; - } - - /* Save current set */ - set = inb(iobase + SSR); - - /* Decide if we should use PIO or DMA transfer */ - if (self->io.speed > PIO_MAX_SPEED) { - self->tx_buff.data = self->tx_buff.head; - skb_copy_from_linear_data(skb, self->tx_buff.data, skb->len); - self->tx_buff.len = skb->len; - - mtt = irda_get_mtt(skb); - pr_debug("%s: %ld, mtt=%d\n", __func__, jiffies, mtt); - if (mtt > 1000) - mdelay(mtt / 1000); - else if (mtt) - udelay(mtt); - - /* Enable DMA interrupt */ - switch_bank(iobase, SET0); - outb(ICR_EDMAI, iobase + ICR); - w83977af_dma_write(self, iobase); - } else { - self->tx_buff.data = self->tx_buff.head; - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - /* Add interrupt on tx low level (will fire immediately) */ - switch_bank(iobase, SET0); - outb(ICR_ETXTHI, iobase + ICR); - } - dev_kfree_skb(skb); - - /* Restore set register */ - outb(set, iobase + SSR); - - return NETDEV_TX_OK; -} - -/* - * Function w83977af_dma_write (self, iobase) - * - * Send frame using DMA - * - */ -static void w83977af_dma_write(struct w83977af_ir *self, int iobase) -{ - __u8 set; - - pr_debug("%s: len=%d\n", __func__, self->tx_buff.len); - - /* Save current set */ - set = inb(iobase + SSR); - - /* Disable DMA */ - switch_bank(iobase, SET0); - outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR); - - /* Choose transmit DMA channel */ - switch_bank(iobase, SET2); - outb(ADCR1_D_CHSW | /*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase + ADCR1); - irda_setup_dma(self->io.dma, self->tx_buff_dma, self->tx_buff.len, - DMA_MODE_WRITE); - self->io.direction = IO_XMIT; - - /* Enable DMA */ - switch_bank(iobase, SET0); - outb(inb(iobase + HCR) | HCR_EN_DMA | HCR_TX_WT, iobase + HCR); - - /* Restore set register */ - outb(set, iobase + SSR); -} - -/* - * Function w83977af_pio_write (iobase, buf, len, fifo_size) - * - * - * - */ -static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size) -{ - int actual = 0; - __u8 set; - - /* Save current bank */ - set = inb(iobase + SSR); - - switch_bank(iobase, SET0); - if (!(inb_p(iobase + USR) & USR_TSRE)) { - pr_debug("%s: warning, FIFO not empty yet!\n", __func__); - - fifo_size -= 17; - pr_debug("%s: %d bytes left in tx fifo\n", __func__, fifo_size); - } - - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual++], iobase + TBR); - } - - pr_debug("%s: fifo_size %d ; %d sent of %d\n", - __func__, fifo_size, actual, len); - - /* Restore bank */ - outb(set, iobase + SSR); - - return actual; -} - -/* - * Function w83977af_dma_xmit_complete (self) - * - * The transfer of a frame in finished. So do the necessary things - * - * - */ -static void w83977af_dma_xmit_complete(struct w83977af_ir *self) -{ - int iobase; - __u8 set; - - pr_debug("%s: %ld\n", __func__, jiffies); - - IRDA_ASSERT(self, return;); - - iobase = self->io.fir_base; - - /* Save current set */ - set = inb(iobase + SSR); - - /* Disable DMA */ - switch_bank(iobase, SET0); - outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR); - - /* Check for underrun! */ - if (inb(iobase + AUDR) & AUDR_UNDR) { - pr_debug("%s: Transmit underrun!\n", __func__); - - self->netdev->stats.tx_errors++; - self->netdev->stats.tx_fifo_errors++; - - /* Clear bit, by writing 1 to it */ - outb(AUDR_UNDR, iobase + AUDR); - } else { - self->netdev->stats.tx_packets++; - } - - if (self->new_speed) { - w83977af_change_speed(self, self->new_speed); - self->new_speed = 0; - } - - /* Unlock tx_buff and request another frame */ - /* Tell the network layer, that we want more frames */ - netif_wake_queue(self->netdev); - - /* Restore set */ - outb(set, iobase + SSR); -} - -/* - * Function w83977af_dma_receive (self) - * - * Get ready for receiving a frame. The device will initiate a DMA - * if it starts to receive a frame. - * - */ -static int w83977af_dma_receive(struct w83977af_ir *self) -{ - int iobase; - __u8 set; -#ifdef CONFIG_ARCH_NETWINDER - unsigned long flags; - __u8 hcr; -#endif - IRDA_ASSERT(self, return -1;); - - pr_debug("%s\n", __func__); - - iobase = self->io.fir_base; - - /* Save current set */ - set = inb(iobase + SSR); - - /* Disable DMA */ - switch_bank(iobase, SET0); - outb(inb(iobase + HCR) & ~HCR_EN_DMA, iobase + HCR); - - /* Choose DMA Rx, DMA Fairness, and Advanced mode */ - switch_bank(iobase, SET2); - outb((inb(iobase + ADCR1) & ~ADCR1_D_CHSW)/*|ADCR1_DMA_F*/ | ADCR1_ADV_SL, - iobase + ADCR1); - - self->io.direction = IO_RECV; - self->rx_buff.data = self->rx_buff.head; - -#ifdef CONFIG_ARCH_NETWINDER - spin_lock_irqsave(&self->lock, flags); - - disable_dma(self->io.dma); - clear_dma_ff(self->io.dma); - set_dma_mode(self->io.dma, DMA_MODE_READ); - set_dma_addr(self->io.dma, self->rx_buff_dma); - set_dma_count(self->io.dma, self->rx_buff.truesize); -#else - irda_setup_dma(self->io.dma, self->rx_buff_dma, self->rx_buff.truesize, - DMA_MODE_READ); -#endif - /* - * Reset Rx FIFO. This will also flush the ST_FIFO, it's very - * important that we don't reset the Tx FIFO since it might not - * be finished transmitting yet - */ - switch_bank(iobase, SET0); - outb(UFR_RXTL | UFR_TXTL | UFR_RXF_RST | UFR_EN_FIFO, iobase + UFR); - self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0; - - /* Enable DMA */ - switch_bank(iobase, SET0); -#ifdef CONFIG_ARCH_NETWINDER - hcr = inb(iobase + HCR); - outb(hcr | HCR_EN_DMA, iobase + HCR); - enable_dma(self->io.dma); - spin_unlock_irqrestore(&self->lock, flags); -#else - outb(inb(iobase + HCR) | HCR_EN_DMA, iobase + HCR); -#endif - /* Restore set */ - outb(set, iobase + SSR); - - return 0; -} - -/* - * Function w83977af_receive_complete (self) - * - * Finished with receiving a frame - * - */ -static int w83977af_dma_receive_complete(struct w83977af_ir *self) -{ - struct sk_buff *skb; - struct st_fifo *st_fifo; - int len; - int iobase; - __u8 set; - __u8 status; - - pr_debug("%s\n", __func__); - - st_fifo = &self->st_fifo; - - iobase = self->io.fir_base; - - /* Save current set */ - set = inb(iobase + SSR); - - iobase = self->io.fir_base; - - /* Read status FIFO */ - switch_bank(iobase, SET5); - while ((status = inb(iobase + FS_FO)) & FS_FO_FSFDR) { - st_fifo->entries[st_fifo->tail].status = status; - - st_fifo->entries[st_fifo->tail].len = inb(iobase + RFLFL); - st_fifo->entries[st_fifo->tail].len |= inb(iobase + RFLFH) << 8; - - st_fifo->tail++; - st_fifo->len++; - } - - while (st_fifo->len) { - /* Get first entry */ - status = st_fifo->entries[st_fifo->head].status; - len = st_fifo->entries[st_fifo->head].len; - st_fifo->head++; - st_fifo->len--; - - /* Check for errors */ - if (status & FS_FO_ERR_MSK) { - if (status & FS_FO_LST_FR) { - /* Add number of lost frames to stats */ - self->netdev->stats.rx_errors += len; - } else { - /* Skip frame */ - self->netdev->stats.rx_errors++; - - self->rx_buff.data += len; - - if (status & FS_FO_MX_LEX) - self->netdev->stats.rx_length_errors++; - - if (status & FS_FO_PHY_ERR) - self->netdev->stats.rx_frame_errors++; - - if (status & FS_FO_CRC_ERR) - self->netdev->stats.rx_crc_errors++; - } - /* The errors below can be reported in both cases */ - if (status & FS_FO_RX_OV) - self->netdev->stats.rx_fifo_errors++; - - if (status & FS_FO_FSF_OV) - self->netdev->stats.rx_fifo_errors++; - - } else { - /* Check if we have transferred all data to memory */ - switch_bank(iobase, SET0); - if (inb(iobase + USR) & USR_RDR) - udelay(80); /* Should be enough!? */ - - skb = dev_alloc_skb(len + 1); - if (!skb) { - pr_info("%s: memory squeeze, dropping frame\n", - __func__); - /* Restore set register */ - outb(set, iobase + SSR); - - return FALSE; - } - - /* Align to 20 bytes */ - skb_reserve(skb, 1); - - /* Copy frame without CRC */ - if (self->io.speed < 4000000) { - skb_put(skb, len - 2); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 2); - } else { - skb_put(skb, len - 4); - skb_copy_to_linear_data(skb, - self->rx_buff.data, - len - 4); - } - - /* Move to next frame */ - self->rx_buff.data += len; - self->netdev->stats.rx_packets++; - - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb->protocol = htons(ETH_P_IRDA); - netif_rx(skb); - } - } - /* Restore set register */ - outb(set, iobase + SSR); - - return TRUE; -} - -/* - * Function pc87108_pio_receive (self) - * - * Receive all data in receiver FIFO - * - */ -static void w83977af_pio_receive(struct w83977af_ir *self) -{ - __u8 byte = 0x00; - int iobase; - - IRDA_ASSERT(self, return;); - - iobase = self->io.fir_base; - - /* Receive all characters in Rx FIFO */ - do { - byte = inb(iobase + RBR); - async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, - byte); - } while (inb(iobase + USR) & USR_RDR); /* Data available */ -} - -/* - * Function w83977af_sir_interrupt (self, eir) - * - * Handle SIR interrupt - * - */ -static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr) -{ - int actual; - __u8 new_icr = 0; - __u8 set; - int iobase; - - pr_debug("%s: isr=%#x\n", __func__, isr); - - iobase = self->io.fir_base; - /* Transmit FIFO low on data */ - if (isr & ISR_TXTH_I) { - /* Write data left in transmit buffer */ - actual = w83977af_pio_write(self->io.fir_base, - self->tx_buff.data, - self->tx_buff.len, - self->io.fifo_size); - - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - - self->io.direction = IO_XMIT; - - /* Check if finished */ - if (self->tx_buff.len > 0) { - new_icr |= ICR_ETXTHI; - } else { - set = inb(iobase + SSR); - switch_bank(iobase, SET0); - outb(AUDR_SFEND, iobase + AUDR); - outb(set, iobase + SSR); - - self->netdev->stats.tx_packets++; - - /* Feed me more packets */ - netif_wake_queue(self->netdev); - new_icr |= ICR_ETBREI; - } - } - /* Check if transmission has completed */ - if (isr & ISR_TXEMP_I) { - /* Check if we need to change the speed? */ - if (self->new_speed) { - pr_debug("%s: Changing speed!\n", __func__); - w83977af_change_speed(self, self->new_speed); - self->new_speed = 0; - } - - /* Turn around and get ready to receive some data */ - self->io.direction = IO_RECV; - new_icr |= ICR_ERBRI; - } - - /* Rx FIFO threshold or timeout */ - if (isr & ISR_RXTH_I) { - w83977af_pio_receive(self); - - /* Keep receiving */ - new_icr |= ICR_ERBRI; - } - return new_icr; -} - -/* - * Function pc87108_fir_interrupt (self, eir) - * - * Handle MIR/FIR interrupt - * - */ -static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr) -{ - __u8 new_icr = 0; - __u8 set; - int iobase; - - iobase = self->io.fir_base; - set = inb(iobase + SSR); - - /* End of frame detected in FIFO */ - if (isr & (ISR_FEND_I | ISR_FSF_I)) { - if (w83977af_dma_receive_complete(self)) { - /* Wait for next status FIFO interrupt */ - new_icr |= ICR_EFSFI; - } else { - /* DMA not finished yet */ - - /* Set timer value, resolution 1 ms */ - switch_bank(iobase, SET4); - outb(0x01, iobase + TMRL); /* 1 ms */ - outb(0x00, iobase + TMRH); - - /* Start timer */ - outb(IR_MSL_EN_TMR, iobase + IR_MSL); - - new_icr |= ICR_ETMRI; - } - } - /* Timer finished */ - if (isr & ISR_TMR_I) { - /* Disable timer */ - switch_bank(iobase, SET4); - outb(0, iobase + IR_MSL); - - /* Clear timer event */ - /* switch_bank(iobase, SET0); */ -/* outb(ASCR_CTE, iobase+ASCR); */ - - /* Check if this is a TX timer interrupt */ - if (self->io.direction == IO_XMIT) { - w83977af_dma_write(self, iobase); - - new_icr |= ICR_EDMAI; - } else { - /* Check if DMA has now finished */ - w83977af_dma_receive_complete(self); - - new_icr |= ICR_EFSFI; - } - } - /* Finished with DMA */ - if (isr & ISR_DMA_I) { - w83977af_dma_xmit_complete(self); - - /* Check if there are more frames to be transmitted */ - /* if (irda_device_txqueue_empty(self)) { */ - - /* Prepare for receive - * - * ** Netwinder Tx DMA likes that we do this anyway ** - */ - w83977af_dma_receive(self); - new_icr = ICR_EFSFI; - /* } */ - } - - /* Restore set */ - outb(set, iobase + SSR); - - return new_icr; -} - -/* - * Function w83977af_interrupt (irq, dev_id, regs) - * - * An interrupt from the chip has arrived. Time to do some work - * - */ -static irqreturn_t w83977af_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct w83977af_ir *self; - __u8 set, icr, isr; - int iobase; - - self = netdev_priv(dev); - - iobase = self->io.fir_base; - - /* Save current bank */ - set = inb(iobase + SSR); - switch_bank(iobase, SET0); - - icr = inb(iobase + ICR); - isr = inb(iobase + ISR) & icr; /* Mask out the interesting ones */ - - outb(0, iobase + ICR); /* Disable interrupts */ - - if (isr) { - /* Dispatch interrupt handler for the current speed */ - if (self->io.speed > PIO_MAX_SPEED) - icr = w83977af_fir_interrupt(self, isr); - else - icr = w83977af_sir_interrupt(self, isr); - } - - outb(icr, iobase + ICR); /* Restore (new) interrupts */ - outb(set, iobase + SSR); /* Restore bank register */ - return IRQ_RETVAL(isr); -} - -/* - * Function w83977af_is_receiving (self) - * - * Return TRUE is we are currently receiving a frame - * - */ -static int w83977af_is_receiving(struct w83977af_ir *self) -{ - int status = FALSE; - int iobase; - __u8 set; - - IRDA_ASSERT(self, return FALSE;); - - if (self->io.speed > 115200) { - iobase = self->io.fir_base; - - /* Check if rx FIFO is not empty */ - set = inb(iobase + SSR); - switch_bank(iobase, SET2); - if ((inb(iobase + RXFDTH) & 0x3f) != 0) { - /* We are receiving something */ - status = TRUE; - } - outb(set, iobase + SSR); - } else { - status = (self->rx_buff.state != OUTSIDE_FRAME); - } - - return status; -} - -/* - * Function w83977af_net_open (dev) - * - * Start the device - * - */ -static int w83977af_net_open(struct net_device *dev) -{ - struct w83977af_ir *self; - int iobase; - char hwname[32]; - __u8 set; - - IRDA_ASSERT(dev, return -1;); - self = netdev_priv(dev); - - IRDA_ASSERT(self, return 0;); - - iobase = self->io.fir_base; - - if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, - (void *)dev)) { - return -EAGAIN; - } - /* - * Always allocate the DMA channel after the IRQ, - * and clean up on failure. - */ - if (request_dma(self->io.dma, dev->name)) { - free_irq(self->io.irq, dev); - return -EAGAIN; - } - - /* Save current set */ - set = inb(iobase + SSR); - - /* Enable some interrupts so we can receive frames again */ - switch_bank(iobase, SET0); - if (self->io.speed > 115200) { - outb(ICR_EFSFI, iobase + ICR); - w83977af_dma_receive(self); - } else { - outb(ICR_ERBRI, iobase + ICR); - } - - /* Restore bank register */ - outb(set, iobase + SSR); - - /* Ready to play! */ - netif_start_queue(dev); - - /* Give self a hardware name */ - sprintf(hwname, "w83977af @ 0x%03x", self->io.fir_base); - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos, hwname); - - return 0; -} - -/* - * Function w83977af_net_close (dev) - * - * Stop the device - * - */ -static int w83977af_net_close(struct net_device *dev) -{ - struct w83977af_ir *self; - int iobase; - __u8 set; - - IRDA_ASSERT(dev, return -1;); - - self = netdev_priv(dev); - - IRDA_ASSERT(self, return 0;); - - iobase = self->io.fir_base; - - /* Stop device */ - netif_stop_queue(dev); - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - disable_dma(self->io.dma); - - /* Save current set */ - set = inb(iobase + SSR); - - /* Disable interrupts */ - switch_bank(iobase, SET0); - outb(0, iobase + ICR); - - free_irq(self->io.irq, dev); - free_dma(self->io.dma); - - /* Restore bank register */ - outb(set, iobase + SSR); - - return 0; -} - -/* - * Function w83977af_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *)rq; - struct w83977af_ir *self; - unsigned long flags; - int ret = 0; - - IRDA_ASSERT(dev, return -1;); - - self = netdev_priv(dev); - - IRDA_ASSERT(self, return -1;); - - pr_debug("%s: %s, (cmd=0x%X)\n", __func__, dev->name, cmd); - - spin_lock_irqsave(&self->lock, flags); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto out; - } - w83977af_change_speed(self, irq->ifr_baudrate); - break; - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - goto out; - } - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = w83977af_is_receiving(self); - break; - default: - ret = -EOPNOTSUPP; - } -out: - spin_unlock_irqrestore(&self->lock, flags); - return ret; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver"); -MODULE_LICENSE("GPL"); - -module_param(qos_mtt_bits, int, 0); -MODULE_PARM_DESC(qos_mtt_bits, "Mimimum Turn Time"); -module_param_hw_array(io, int, ioport, NULL, 0); -MODULE_PARM_DESC(io, "Base I/O addresses"); -module_param_hw_array(irq, int, irq, NULL, 0); -MODULE_PARM_DESC(irq, "IRQ lines"); - -/* - * Function init_module (void) - * - * - * - */ -module_init(w83977af_init); - -/* - * Function cleanup_module (void) - * - * - * - */ -module_exit(w83977af_cleanup); diff --git a/drivers/staging/irda/drivers/w83977af_ir.h b/drivers/staging/irda/drivers/w83977af_ir.h deleted file mode 100644 index fefe9b11e200..000000000000 --- a/drivers/staging/irda/drivers/w83977af_ir.h +++ /dev/null @@ -1,198 +0,0 @@ -/********************************************************************* - * - * Filename: w83977af_ir.h - * Version: - * Description: - * Status: Experimental. - * Author: Paul VanderSpek - * Created at: Thu Nov 19 13:55:34 1998 - * Modified at: Tue Jan 11 13:08:19 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef W83977AF_IR_H -#define W83977AF_IR_H - -#include <asm/io.h> -#include <linux/types.h> - -/* Flags for configuration register CRF0 */ -#define ENBNKSEL 0x01 -#define APEDCRC 0x02 -#define TXW4C 0x04 -#define RXW4C 0x08 - -/* Bank 0 */ -#define RBR 0x00 /* Receiver buffer register */ -#define TBR 0x00 /* Transmitter buffer register */ - -#define ICR 0x01 /* Interrupt configuration register */ -#define ICR_ERBRI 0x01 /* Receiver buffer register interrupt */ -#define ICR_ETBREI 0x02 /* Transeiver empty interrupt */ -#define ICR_EUSRI 0x04//* IR status interrupt */ -#define ICR_EHSRI 0x04 -#define ICR_ETXURI 0x04 /* Tx underrun */ -#define ICR_EDMAI 0x10 /* DMA interrupt */ -#define ICR_ETXTHI 0x20 /* Transmitter threshold interrupt */ -#define ICR_EFSFI 0x40 /* Frame status FIFO interrupt */ -#define ICR_ETMRI 0x80 /* Timer interrupt */ - -#define UFR 0x02 /* FIFO control register */ -#define UFR_EN_FIFO 0x01 /* Enable FIFO's */ -#define UFR_RXF_RST 0x02 /* Reset Rx FIFO */ -#define UFR_TXF_RST 0x04 /* Reset Tx FIFO */ -#define UFR_RXTL 0x80 /* Rx FIFO threshold (set to 16) */ -#define UFR_TXTL 0x20 /* Tx FIFO threshold (set to 17) */ - -#define ISR 0x02 /* Interrupt status register */ -#define ISR_RXTH_I 0x01 /* Receive threshold interrupt */ -#define ISR_TXEMP_I 0x02 /* Transmitter empty interrupt */ -#define ISR_FEND_I 0x04 -#define ISR_DMA_I 0x10 -#define ISR_TXTH_I 0x20 /* Transmitter threshold interrupt */ -#define ISR_FSF_I 0x40 -#define ISR_TMR_I 0x80 /* Timer interrupt */ - -#define UCR 0x03 /* Uart control register */ -#define UCR_DLS8 0x03 /* 8N1 */ - -#define SSR 0x03 /* Sets select register */ -#define SET0 UCR_DLS8 /* Make sure we keep 8N1 */ -#define SET1 (0x80|UCR_DLS8) /* Make sure we keep 8N1 */ -#define SET2 0xE0 -#define SET3 0xE4 -#define SET4 0xE8 -#define SET5 0xEC -#define SET6 0xF0 -#define SET7 0xF4 - -#define HCR 0x04 -#define HCR_MODE_MASK ~(0xD0) -#define HCR_SIR 0x60 -#define HCR_MIR_576 0x20 -#define HCR_MIR_1152 0x80 -#define HCR_FIR 0xA0 -#define HCR_EN_DMA 0x04 -#define HCR_EN_IRQ 0x08 -#define HCR_TX_WT 0x08 - -#define USR 0x05 /* IR status register */ -#define USR_RDR 0x01 /* Receive data ready */ -#define USR_TSRE 0x40 /* Transmitter empty? */ - -#define AUDR 0x07 -#define AUDR_SFEND 0x08 /* Set a frame end */ -#define AUDR_RXBSY 0x20 /* Rx busy */ -#define AUDR_UNDR 0x40 /* Transeiver underrun */ - -/* Set 2 */ -#define ABLL 0x00 /* Advanced baud rate divisor latch (low byte) */ -#define ABHL 0x01 /* Advanced baud rate divisor latch (high byte) */ - -#define ADCR1 0x02 -#define ADCR1_ADV_SL 0x01 -#define ADCR1_D_CHSW 0x08 /* the specs are wrong. its bit 3, not 4 */ -#define ADCR1_DMA_F 0x02 - -#define ADCR2 0x04 -#define ADCR2_TXFS32 0x01 -#define ADCR2_RXFS32 0x04 - -#define RXFDTH 0x07 - -/* Set 3 */ -#define AUID 0x00 - -/* Set 4 */ -#define TMRL 0x00 /* Timer value register (low byte) */ -#define TMRH 0x01 /* Timer value register (high byte) */ - -#define IR_MSL 0x02 /* Infrared mode select */ -#define IR_MSL_EN_TMR 0x01 /* Enable timer */ - -#define TFRLL 0x04 /* Transmitter frame length (low byte) */ -#define TFRLH 0x05 /* Transmitter frame length (high byte) */ -#define RFRLL 0x06 /* Receiver frame length (low byte) */ -#define RFRLH 0x07 /* Receiver frame length (high byte) */ - -/* Set 5 */ - -#define FS_FO 0x05 /* Frame status FIFO */ -#define FS_FO_FSFDR 0x80 /* Frame status FIFO data ready */ -#define FS_FO_LST_FR 0x40 /* Frame lost */ -#define FS_FO_MX_LEX 0x10 /* Max frame len exceeded */ -#define FS_FO_PHY_ERR 0x08 /* Physical layer error */ -#define FS_FO_CRC_ERR 0x04 -#define FS_FO_RX_OV 0x02 /* Receive overrun */ -#define FS_FO_FSF_OV 0x01 /* Frame status FIFO overrun */ -#define FS_FO_ERR_MSK 0x5f /* Error mask */ - -#define RFLFL 0x06 -#define RFLFH 0x07 - -/* Set 6 */ -#define IR_CFG2 0x00 -#define IR_CFG2_DIS_CRC 0x02 - -/* Set 7 */ -#define IRM_CR 0x07 /* Infrared module control register */ -#define IRM_CR_IRX_MSL 0x40 -#define IRM_CR_AF_MNT 0x80 /* Automatic format */ - -/* For storing entries in the status FIFO */ -struct st_fifo_entry { - int status; - int len; -}; - -struct st_fifo { - struct st_fifo_entry entries[10]; - int head; - int tail; - int len; -}; - -/* Private data for each instance */ -struct w83977af_ir { - struct st_fifo st_fifo; - - int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */ - int tx_len; /* Number of frames in tx_buff */ - - struct net_device *netdev; /* Yes! we are some kind of netdevice */ - - struct irlap_cb *irlap; /* The link layer we are binded to */ - struct qos_info qos; /* QoS capabilities for this device */ - - chipio_t io; /* IrDA controller information */ - iobuff_t tx_buff; /* Transmit buffer */ - iobuff_t rx_buff; /* Receive buffer */ - dma_addr_t tx_buff_dma; - dma_addr_t rx_buff_dma; - - /* Note : currently locking is *very* incomplete, but this - * will get you started. Check in nsc-ircc.c for a proper - * locking strategy. - Jean II */ - spinlock_t lock; /* For serializing operations */ - - __u32 new_speed; -}; - -static inline void switch_bank( int iobase, int set) -{ - outb(set, iobase+SSR); -} - -#endif diff --git a/drivers/staging/irda/include/net/irda/af_irda.h b/drivers/staging/irda/include/net/irda/af_irda.h deleted file mode 100644 index 0df574931522..000000000000 --- a/drivers/staging/irda/include/net/irda/af_irda.h +++ /dev/null @@ -1,87 +0,0 @@ -/********************************************************************* - * - * Filename: af_irda.h - * Version: 1.0 - * Description: IrDA sockets declarations - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Dec 9 21:13:12 1997 - * Modified at: Fri Jan 28 13:16:32 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef AF_IRDA_H -#define AF_IRDA_H - -#include <linux/irda.h> -#include <net/irda/irda.h> -#include <net/irda/iriap.h> /* struct iriap_cb */ -#include <net/irda/irias_object.h> /* struct ias_value */ -#include <net/irda/irlmp.h> /* struct lsap_cb */ -#include <net/irda/irttp.h> /* struct tsap_cb */ -#include <net/irda/discovery.h> /* struct discovery_t */ -#include <net/sock.h> - -/* IrDA Socket */ -struct irda_sock { - /* struct sock has to be the first member of irda_sock */ - struct sock sk; - __u32 saddr; /* my local address */ - __u32 daddr; /* peer address */ - - struct lsap_cb *lsap; /* LSAP used by Ultra */ - __u8 pid; /* Protocol IP (PID) used by Ultra */ - - struct tsap_cb *tsap; /* TSAP used by this connection */ - __u8 dtsap_sel; /* remote TSAP address */ - __u8 stsap_sel; /* local TSAP address */ - - __u32 max_sdu_size_rx; - __u32 max_sdu_size_tx; - __u32 max_data_size; - __u8 max_header_size; - struct qos_info qos_tx; - - __u16_host_order mask; /* Hint bits mask */ - __u16_host_order hints; /* Hint bits */ - - void *ckey; /* IrLMP client handle */ - void *skey; /* IrLMP service handle */ - - struct ias_object *ias_obj; /* Our service name + lsap in IAS */ - struct iriap_cb *iriap; /* Used to query remote IAS */ - struct ias_value *ias_result; /* Result of remote IAS query */ - - hashbin_t *cachelog; /* Result of discovery query */ - __u32 cachedaddr; /* Result of selective discovery query */ - - int nslots; /* Number of slots to use for discovery */ - - int errno; /* status of the IAS query */ - - wait_queue_head_t query_wait; /* Wait for the answer to a query */ - struct timer_list watchdog; /* Timeout for discovery */ - - LOCAL_FLOW tx_flow; - LOCAL_FLOW rx_flow; -}; - -static inline struct irda_sock *irda_sk(struct sock *sk) -{ - return (struct irda_sock *)sk; -} - -#endif /* AF_IRDA_H */ diff --git a/drivers/staging/irda/include/net/irda/crc.h b/drivers/staging/irda/include/net/irda/crc.h deleted file mode 100644 index f202296df9bb..000000000000 --- a/drivers/staging/irda/include/net/irda/crc.h +++ /dev/null @@ -1,29 +0,0 @@ -/********************************************************************* - * - * Filename: crc.h - * Version: - * Description: CRC routines - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Sun May 2 20:25:23 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - ********************************************************************/ - -#ifndef IRDA_CRC_H -#define IRDA_CRC_H - -#include <linux/types.h> -#include <linux/crc-ccitt.h> - -#define INIT_FCS 0xffff /* Initial FCS value */ -#define GOOD_FCS 0xf0b8 /* Good final FCS value */ - -/* Recompute the FCS with one more character appended. */ -#define irda_fcs(fcs, c) crc_ccitt_byte(fcs, c) - -/* Recompute the FCS with len bytes appended. */ -#define irda_calc_crc16(fcs, buf, len) crc_ccitt(fcs, buf, len) - -#endif diff --git a/drivers/staging/irda/include/net/irda/discovery.h b/drivers/staging/irda/include/net/irda/discovery.h deleted file mode 100644 index 63ae32530567..000000000000 --- a/drivers/staging/irda/include/net/irda/discovery.h +++ /dev/null @@ -1,95 +0,0 @@ -/********************************************************************* - * - * Filename: discovery.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Apr 6 16:53:53 1999 - * Modified at: Tue Oct 5 10:05:10 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef DISCOVERY_H -#define DISCOVERY_H - -#include <asm/param.h> - -#include <net/irda/irda.h> -#include <net/irda/irqueue.h> /* irda_queue_t */ -#include <net/irda/irlap_event.h> /* LAP_REASON */ - -#define DISCOVERY_EXPIRE_TIMEOUT (2*sysctl_discovery_timeout*HZ) -#define DISCOVERY_DEFAULT_SLOTS 0 - -/* - * This type is used by the protocols that transmit 16 bits words in - * little endian format. A little endian machine stores MSB of word in - * byte[1] and LSB in byte[0]. A big endian machine stores MSB in byte[0] - * and LSB in byte[1]. - * - * This structure is used in the code for things that are endian neutral - * but that fit in a word so that we can manipulate them efficiently. - * By endian neutral, I mean things that are really an array of bytes, - * and always used as such, for example the hint bits. Jean II - */ -typedef union { - __u16 word; - __u8 byte[2]; -} __u16_host_order; - -/* Types of discovery */ -typedef enum { - DISCOVERY_LOG, /* What's in our discovery log */ - DISCOVERY_ACTIVE, /* Doing our own discovery on the medium */ - DISCOVERY_PASSIVE, /* Peer doing discovery on the medium */ - EXPIRY_TIMEOUT, /* Entry expired due to timeout */ -} DISCOVERY_MODE; - -#define NICKNAME_MAX_LEN 21 - -/* Basic discovery information about a peer */ -typedef struct irda_device_info discinfo_t; /* linux/irda.h */ - -/* - * The DISCOVERY structure is used for both discovery requests and responses - */ -typedef struct discovery_t { - irda_queue_t q; /* Must be first! */ - - discinfo_t data; /* Basic discovery information */ - int name_len; /* Length of nickname */ - - LAP_REASON condition; /* More info about the discovery */ - int gen_addr_bit; /* Need to generate a new device - * address? */ - int nslots; /* Number of slots to use when - * discovering */ - unsigned long timestamp; /* Last time discovered */ - unsigned long firststamp; /* First time discovered */ -} discovery_t; - -void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery); -void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log); -void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force); -struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, - __u16 mask, int old_entries); - -#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_core.h b/drivers/staging/irda/include/net/irda/ircomm_core.h deleted file mode 100644 index 2a580ce9edad..000000000000 --- a/drivers/staging/irda/include/net/irda/ircomm_core.h +++ /dev/null @@ -1,106 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_core.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Wed Jun 9 08:58:43 1999 - * Modified at: Mon Dec 13 11:52:29 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRCOMM_CORE_H -#define IRCOMM_CORE_H - -#include <net/irda/irda.h> -#include <net/irda/irqueue.h> -#include <net/irda/ircomm_event.h> - -#define IRCOMM_MAGIC 0x98347298 -#define IRCOMM_HEADER_SIZE 1 - -struct ircomm_cb; /* Forward decl. */ - -/* - * A small call-table, so we don't have to check the service-type whenever - * we want to do something - */ -typedef struct { - int (*data_request)(struct ircomm_cb *, struct sk_buff *, int clen); - int (*connect_request)(struct ircomm_cb *, struct sk_buff *, - struct ircomm_info *); - int (*connect_response)(struct ircomm_cb *, struct sk_buff *); - int (*disconnect_request)(struct ircomm_cb *, struct sk_buff *, - struct ircomm_info *); -} call_t; - -struct ircomm_cb { - irda_queue_t queue; - magic_t magic; - - notify_t notify; - call_t issue; - - int state; - int line; /* Which TTY line we are using */ - - struct tsap_cb *tsap; - struct lsap_cb *lsap; - - __u8 dlsap_sel; /* Destination LSAP/TSAP selector */ - __u8 slsap_sel; /* Source LSAP/TSAP selector */ - - __u32 saddr; /* Source device address (link we are using) */ - __u32 daddr; /* Destination device address */ - - int max_header_size; /* Header space we must reserve for each frame */ - int max_data_size; /* The amount of data we can fill in each frame */ - - LOCAL_FLOW flow_status; /* Used by ircomm_lmp */ - int pkt_count; /* Number of frames we have sent to IrLAP */ - - __u8 service_type; -}; - -extern hashbin_t *ircomm; - -struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line); -int ircomm_close(struct ircomm_cb *self); - -int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb); -void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb); -void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb); -int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb); -int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, - __u32 saddr, __u32 daddr, struct sk_buff *skb, - __u8 service_type); -void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, - struct ircomm_info *info); -void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, - struct ircomm_info *info); -int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata); -int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata); -void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, - struct ircomm_info *info); -void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow); - -#define ircomm_is_connected(self) (self->state == IRCOMM_CONN) - -#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_event.h b/drivers/staging/irda/include/net/irda/ircomm_event.h deleted file mode 100644 index 5bbc32998d57..000000000000 --- a/drivers/staging/irda/include/net/irda/ircomm_event.h +++ /dev/null @@ -1,83 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_event.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Jun 6 23:51:13 1999 - * Modified at: Thu Jun 10 08:36:25 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRCOMM_EVENT_H -#define IRCOMM_EVENT_H - -#include <net/irda/irmod.h> - -typedef enum { - IRCOMM_IDLE, - IRCOMM_WAITI, - IRCOMM_WAITR, - IRCOMM_CONN, -} IRCOMM_STATE; - -/* IrCOMM Events */ -typedef enum { - IRCOMM_CONNECT_REQUEST, - IRCOMM_CONNECT_RESPONSE, - IRCOMM_TTP_CONNECT_INDICATION, - IRCOMM_LMP_CONNECT_INDICATION, - IRCOMM_TTP_CONNECT_CONFIRM, - IRCOMM_LMP_CONNECT_CONFIRM, - - IRCOMM_LMP_DISCONNECT_INDICATION, - IRCOMM_TTP_DISCONNECT_INDICATION, - IRCOMM_DISCONNECT_REQUEST, - - IRCOMM_TTP_DATA_INDICATION, - IRCOMM_LMP_DATA_INDICATION, - IRCOMM_DATA_REQUEST, - IRCOMM_CONTROL_REQUEST, - IRCOMM_CONTROL_INDICATION, -} IRCOMM_EVENT; - -/* - * Used for passing information through the state-machine - */ -struct ircomm_info { - __u32 saddr; /* Source device address */ - __u32 daddr; /* Destination device address */ - __u8 dlsap_sel; - LM_REASON reason; /* Reason for disconnect */ - __u32 max_data_size; - __u32 max_header_size; - - struct qos_info *qos; -}; - -extern const char *const ircomm_state[]; - -struct ircomm_cb; /* Forward decl. */ - -int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info); -void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state); - -#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_lmp.h b/drivers/staging/irda/include/net/irda/ircomm_lmp.h deleted file mode 100644 index 5042a5021a04..000000000000 --- a/drivers/staging/irda/include/net/irda/ircomm_lmp.h +++ /dev/null @@ -1,36 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_lmp.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Wed Jun 9 10:06:07 1999 - * Modified at: Fri Aug 13 07:32:32 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRCOMM_LMP_H -#define IRCOMM_LMP_H - -#include <net/irda/ircomm_core.h> - -int ircomm_open_lsap(struct ircomm_cb *self); - -#endif diff --git a/drivers/staging/irda/include/net/irda/ircomm_param.h b/drivers/staging/irda/include/net/irda/ircomm_param.h deleted file mode 100644 index 1f67432321c4..000000000000 --- a/drivers/staging/irda/include/net/irda/ircomm_param.h +++ /dev/null @@ -1,147 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_param.h - * Version: 1.0 - * Description: Parameter handling for the IrCOMM protocol - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Jun 7 08:47:28 1999 - * Modified at: Wed Aug 25 13:46:33 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRCOMM_PARAMS_H -#define IRCOMM_PARAMS_H - -#include <net/irda/parameters.h> - -/* Parameters common to all service types */ -#define IRCOMM_SERVICE_TYPE 0x00 -#define IRCOMM_PORT_TYPE 0x01 /* Only used in LM-IAS */ -#define IRCOMM_PORT_NAME 0x02 /* Only used in LM-IAS */ - -/* Parameters for both 3 wire and 9 wire */ -#define IRCOMM_DATA_RATE 0x10 -#define IRCOMM_DATA_FORMAT 0x11 -#define IRCOMM_FLOW_CONTROL 0x12 -#define IRCOMM_XON_XOFF 0x13 -#define IRCOMM_ENQ_ACK 0x14 -#define IRCOMM_LINE_STATUS 0x15 -#define IRCOMM_BREAK 0x16 - -/* Parameters for 9 wire */ -#define IRCOMM_DTE 0x20 -#define IRCOMM_DCE 0x21 -#define IRCOMM_POLL 0x22 - -/* Service type (details) */ -#define IRCOMM_3_WIRE_RAW 0x01 -#define IRCOMM_3_WIRE 0x02 -#define IRCOMM_9_WIRE 0x04 -#define IRCOMM_CENTRONICS 0x08 - -/* Port type (details) */ -#define IRCOMM_SERIAL 0x00 -#define IRCOMM_PARALLEL 0x01 - -/* Data format (details) */ -#define IRCOMM_WSIZE_5 0x00 -#define IRCOMM_WSIZE_6 0x01 -#define IRCOMM_WSIZE_7 0x02 -#define IRCOMM_WSIZE_8 0x03 - -#define IRCOMM_1_STOP_BIT 0x00 -#define IRCOMM_2_STOP_BIT 0x04 /* 1.5 if char len 5 */ - -#define IRCOMM_PARITY_DISABLE 0x00 -#define IRCOMM_PARITY_ENABLE 0x08 - -#define IRCOMM_PARITY_ODD 0x00 -#define IRCOMM_PARITY_EVEN 0x10 -#define IRCOMM_PARITY_MARK 0x20 -#define IRCOMM_PARITY_SPACE 0x30 - -/* Flow control */ -#define IRCOMM_XON_XOFF_IN 0x01 -#define IRCOMM_XON_XOFF_OUT 0x02 -#define IRCOMM_RTS_CTS_IN 0x04 -#define IRCOMM_RTS_CTS_OUT 0x08 -#define IRCOMM_DSR_DTR_IN 0x10 -#define IRCOMM_DSR_DTR_OUT 0x20 -#define IRCOMM_ENQ_ACK_IN 0x40 -#define IRCOMM_ENQ_ACK_OUT 0x80 - -/* Line status */ -#define IRCOMM_OVERRUN_ERROR 0x02 -#define IRCOMM_PARITY_ERROR 0x04 -#define IRCOMM_FRAMING_ERROR 0x08 - -/* DTE (Data terminal equipment) line settings */ -#define IRCOMM_DELTA_DTR 0x01 -#define IRCOMM_DELTA_RTS 0x02 -#define IRCOMM_DTR 0x04 -#define IRCOMM_RTS 0x08 - -/* DCE (Data communications equipment) line settings */ -#define IRCOMM_DELTA_CTS 0x01 /* Clear to send has changed */ -#define IRCOMM_DELTA_DSR 0x02 /* Data set ready has changed */ -#define IRCOMM_DELTA_RI 0x04 /* Ring indicator has changed */ -#define IRCOMM_DELTA_CD 0x08 /* Carrier detect has changed */ -#define IRCOMM_CTS 0x10 /* Clear to send is high */ -#define IRCOMM_DSR 0x20 /* Data set ready is high */ -#define IRCOMM_RI 0x40 /* Ring indicator is high */ -#define IRCOMM_CD 0x80 /* Carrier detect is high */ -#define IRCOMM_DCE_DELTA_ANY 0x0f - -/* - * Parameter state - */ -struct ircomm_params { - /* General control params */ - __u8 service_type; - __u8 port_type; - char port_name[32]; - - /* Control params for 3- and 9-wire service type */ - __u32 data_rate; /* Data rate in bps */ - __u8 data_format; - __u8 flow_control; - char xonxoff[2]; - char enqack[2]; - __u8 line_status; - __u8 _break; - - __u8 null_modem; - - /* Control params for 9-wire service type */ - __u8 dte; - __u8 dce; - __u8 poll; - - /* Control params for Centronics service type */ -}; - -struct ircomm_tty_cb; /* Forward decl. */ - -int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush); - -extern pi_param_info_t ircomm_param_info; - -#endif /* IRCOMM_PARAMS_H */ - diff --git a/drivers/staging/irda/include/net/irda/ircomm_ttp.h b/drivers/staging/irda/include/net/irda/ircomm_ttp.h deleted file mode 100644 index c5627288bca3..000000000000 --- a/drivers/staging/irda/include/net/irda/ircomm_ttp.h +++ /dev/null @@ -1,37 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_ttp.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Wed Jun 9 10:06:07 1999 - * Modified at: Fri Aug 13 07:32:22 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRCOMM_TTP_H -#define IRCOMM_TTP_H - -#include <net/irda/ircomm_core.h> - -int ircomm_open_tsap(struct ircomm_cb *self); - -#endif - diff --git a/drivers/staging/irda/include/net/irda/ircomm_tty.h b/drivers/staging/irda/include/net/irda/ircomm_tty.h deleted file mode 100644 index 8d4f588974bc..000000000000 --- a/drivers/staging/irda/include/net/irda/ircomm_tty.h +++ /dev/null @@ -1,121 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_tty.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Jun 6 23:24:22 1999 - * Modified at: Fri Jan 28 13:16:57 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRCOMM_TTY_H -#define IRCOMM_TTY_H - -#include <linux/serial.h> -#include <linux/termios.h> -#include <linux/timer.h> -#include <linux/tty.h> /* struct tty_struct */ - -#include <net/irda/irias_object.h> -#include <net/irda/ircomm_core.h> -#include <net/irda/ircomm_param.h> - -#define IRCOMM_TTY_PORTS 32 -#define IRCOMM_TTY_MAGIC 0x3432 -#define IRCOMM_TTY_MAJOR 161 -#define IRCOMM_TTY_MINOR 0 - -/* This is used as an initial value to max_header_size before the proper - * value is filled in (5 for ttp, 4 for lmp). This allow us to detect - * the state of the underlying connection. - Jean II */ -#define IRCOMM_TTY_HDR_UNINITIALISED 16 -/* Same for payload size. See qos.c for the smallest max data size */ -#define IRCOMM_TTY_DATA_UNINITIALISED (64 - IRCOMM_TTY_HDR_UNINITIALISED) - -/* - * IrCOMM TTY driver state - */ -struct ircomm_tty_cb { - irda_queue_t queue; /* Must be first */ - struct tty_port port; - magic_t magic; - - int state; /* Connect state */ - - struct ircomm_cb *ircomm; /* IrCOMM layer instance */ - - struct sk_buff *tx_skb; /* Transmit buffer */ - struct sk_buff *ctrl_skb; /* Control data buffer */ - - /* Parameters */ - struct ircomm_params settings; - - __u8 service_type; /* The service that we support */ - int client; /* True if we are a client */ - LOCAL_FLOW flow; /* IrTTP flow status */ - - int line; - - __u8 dlsap_sel; - __u8 slsap_sel; - - __u32 saddr; - __u32 daddr; - - __u32 max_data_size; /* Max data we can transmit in one packet */ - __u32 max_header_size; /* The amount of header space we must reserve */ - __u32 tx_data_size; /* Max data size of current tx_skb */ - - struct iriap_cb *iriap; /* Instance used for querying remote IAS */ - struct ias_object* obj; - void *skey; - void *ckey; - - struct timer_list watchdog_timer; - struct work_struct tqueue; - - /* Protect concurent access to : - * o self->ctrl_skb - * o self->tx_skb - * Maybe other things may gain to be protected as well... - * Jean II */ - spinlock_t spinlock; -}; - -void ircomm_tty_start(struct tty_struct *tty); -void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self); - -int ircomm_tty_tiocmget(struct tty_struct *tty); -int ircomm_tty_tiocmset(struct tty_struct *tty, unsigned int set, - unsigned int clear); -int ircomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg); -void ircomm_tty_set_termios(struct tty_struct *tty, - struct ktermios *old_termios); - -#endif - - - - - - - diff --git a/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h b/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h deleted file mode 100644 index 20dcbdf258cf..000000000000 --- a/drivers/staging/irda/include/net/irda/ircomm_tty_attach.h +++ /dev/null @@ -1,92 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_tty_attach.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Wed Jun 9 15:55:18 1999 - * Modified at: Fri Dec 10 21:04:55 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRCOMM_TTY_ATTACH_H -#define IRCOMM_TTY_ATTACH_H - -#include <net/irda/ircomm_tty.h> - -typedef enum { - IRCOMM_TTY_IDLE, - IRCOMM_TTY_SEARCH, - IRCOMM_TTY_QUERY_PARAMETERS, - IRCOMM_TTY_QUERY_LSAP_SEL, - IRCOMM_TTY_SETUP, - IRCOMM_TTY_READY, -} IRCOMM_TTY_STATE; - -/* IrCOMM TTY Events */ -typedef enum { - IRCOMM_TTY_ATTACH_CABLE, - IRCOMM_TTY_DETACH_CABLE, - IRCOMM_TTY_DATA_REQUEST, - IRCOMM_TTY_DATA_INDICATION, - IRCOMM_TTY_DISCOVERY_REQUEST, - IRCOMM_TTY_DISCOVERY_INDICATION, - IRCOMM_TTY_CONNECT_CONFIRM, - IRCOMM_TTY_CONNECT_INDICATION, - IRCOMM_TTY_DISCONNECT_REQUEST, - IRCOMM_TTY_DISCONNECT_INDICATION, - IRCOMM_TTY_WD_TIMER_EXPIRED, - IRCOMM_TTY_GOT_PARAMETERS, - IRCOMM_TTY_GOT_LSAPSEL, -} IRCOMM_TTY_EVENT; - -/* Used for passing information through the state-machine */ -struct ircomm_tty_info { - __u32 saddr; /* Source device address */ - __u32 daddr; /* Destination device address */ - __u8 dlsap_sel; -}; - -extern const char *const ircomm_state[]; -extern const char *const ircomm_tty_state[]; - -int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, - struct sk_buff *skb, struct ircomm_tty_info *info); - - -int ircomm_tty_attach_cable(struct ircomm_tty_cb *self); -void ircomm_tty_detach_cable(struct ircomm_tty_cb *self); -void ircomm_tty_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb); -void ircomm_tty_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *skb); -void ircomm_tty_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb); -int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self); -void ircomm_tty_link_established(struct ircomm_tty_cb *self); - -#endif /* IRCOMM_TTY_ATTACH_H */ diff --git a/drivers/staging/irda/include/net/irda/irda.h b/drivers/staging/irda/include/net/irda/irda.h deleted file mode 100644 index 92c8fb575213..000000000000 --- a/drivers/staging/irda/include/net/irda/irda.h +++ /dev/null @@ -1,115 +0,0 @@ -/********************************************************************* - * - * Filename: irda.h - * Version: 1.0 - * Description: IrDA common include file for kernel internal use - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Dec 9 21:13:12 1997 - * Modified at: Fri Jan 28 13:16:32 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef NET_IRDA_H -#define NET_IRDA_H - -#include <linux/skbuff.h> /* struct sk_buff */ -#include <linux/kernel.h> -#include <linux/if.h> /* sa_family_t in <linux/irda.h> */ -#include <linux/irda.h> - -typedef __u32 magic_t; - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -/* Hack to do small backoff when setting media busy in IrLAP */ -#ifndef SMALL -#define SMALL 5 -#endif - -#ifndef IRDA_MIN /* Lets not mix this MIN with other header files */ -#define IRDA_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -#ifndef IRDA_ALIGN -# define IRDA_ALIGN __attribute__((aligned)) -#endif - -#ifdef CONFIG_IRDA_DEBUG -#define IRDA_ASSERT(expr, func) \ -do { if(!(expr)) { \ - printk( "Assertion failed! %s:%s:%d %s\n", \ - __FILE__,__func__,__LINE__,(#expr) ); \ - func } } while (0) -#define IRDA_ASSERT_LABEL(label) label -#else -#define IRDA_ASSERT(expr, func) do { (void)(expr); } while (0) -#define IRDA_ASSERT_LABEL(label) -#endif /* CONFIG_IRDA_DEBUG */ - -/* - * Magic numbers used by Linux-IrDA. Random numbers which must be unique to - * give the best protection - */ - -#define IRTTY_MAGIC 0x2357 -#define LAP_MAGIC 0x1357 -#define LMP_MAGIC 0x4321 -#define LMP_LSAP_MAGIC 0x69333 -#define LMP_LAP_MAGIC 0x3432 -#define IRDA_DEVICE_MAGIC 0x63454 -#define IAS_MAGIC 0x007 -#define TTP_MAGIC 0x241169 -#define TTP_TSAP_MAGIC 0x4345 -#define IROBEX_MAGIC 0x341324 -#define HB_MAGIC 0x64534 -#define IRLAN_MAGIC 0x754 -#define IAS_OBJECT_MAGIC 0x34234 -#define IAS_ATTRIB_MAGIC 0x45232 -#define IRDA_TASK_MAGIC 0x38423 - -#define IAS_DEVICE_ID 0x0000 /* Defined by IrDA, IrLMP section 4.1 (page 68) */ -#define IAS_PNP_ID 0xd342 -#define IAS_OBEX_ID 0x34323 -#define IAS_IRLAN_ID 0x34234 -#define IAS_IRCOMM_ID 0x2343 -#define IAS_IRLPT_ID 0x9876 - -struct net_device; -struct packet_type; - -void irda_proc_register(void); -void irda_proc_unregister(void); - -int irda_sysctl_register(void); -void irda_sysctl_unregister(void); - -int irsock_init(void); -void irsock_cleanup(void); - -int irda_nl_register(void); -void irda_nl_unregister(void); - -int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *orig_dev); - -#endif /* NET_IRDA_H */ diff --git a/drivers/staging/irda/include/net/irda/irda_device.h b/drivers/staging/irda/include/net/irda/irda_device.h deleted file mode 100644 index 664bf8178412..000000000000 --- a/drivers/staging/irda/include/net/irda/irda_device.h +++ /dev/null @@ -1,285 +0,0 @@ -/********************************************************************* - * - * Filename: irda_device.h - * Version: 0.9 - * Description: Contains various declarations used by the drivers - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Apr 14 12:41:42 1998 - * Modified at: Mon Mar 20 09:08:57 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>, - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -/* - * This header contains all the IrDA definitions a driver really - * needs, and therefore the driver should not need to include - * any other IrDA headers - Jean II - */ - -#ifndef IRDA_DEVICE_H -#define IRDA_DEVICE_H - -#include <linux/tty.h> -#include <linux/netdevice.h> -#include <linux/spinlock.h> -#include <linux/skbuff.h> /* struct sk_buff */ -#include <linux/irda.h> -#include <linux/types.h> - -#include <net/pkt_sched.h> -#include <net/irda/irda.h> -#include <net/irda/qos.h> /* struct qos_info */ -#include <net/irda/irqueue.h> /* irda_queue_t */ - -/* A few forward declarations (to make compiler happy) */ -struct irlap_cb; - -/* Some non-standard interface flags (should not conflict with any in if.h) */ -#define IFF_SIR 0x0001 /* Supports SIR speeds */ -#define IFF_MIR 0x0002 /* Supports MIR speeds */ -#define IFF_FIR 0x0004 /* Supports FIR speeds */ -#define IFF_VFIR 0x0008 /* Supports VFIR speeds */ -#define IFF_PIO 0x0010 /* Supports PIO transfer of data */ -#define IFF_DMA 0x0020 /* Supports DMA transfer of data */ -#define IFF_SHM 0x0040 /* Supports shared memory data transfers */ -#define IFF_DONGLE 0x0080 /* Interface has a dongle attached */ -#define IFF_AIR 0x0100 /* Supports Advanced IR (AIR) standards */ - -#define IO_XMIT 0x01 -#define IO_RECV 0x02 - -typedef enum { - IRDA_IRLAP, /* IrDA mode, and deliver to IrLAP */ - IRDA_RAW, /* IrDA mode */ - SHARP_ASK, - TV_REMOTE, /* Also known as Consumer Electronics IR */ -} INFRARED_MODE; - -typedef enum { - IRDA_TASK_INIT, /* All tasks are initialized with this state */ - IRDA_TASK_DONE, /* Signals that the task is finished */ - IRDA_TASK_WAIT, - IRDA_TASK_WAIT1, - IRDA_TASK_WAIT2, - IRDA_TASK_WAIT3, - IRDA_TASK_CHILD_INIT, /* Initializing child task */ - IRDA_TASK_CHILD_WAIT, /* Waiting for child task to finish */ - IRDA_TASK_CHILD_DONE /* Child task is finished */ -} IRDA_TASK_STATE; - -struct irda_task; -typedef int (*IRDA_TASK_CALLBACK) (struct irda_task *task); - -struct irda_task { - irda_queue_t q; - magic_t magic; - - IRDA_TASK_STATE state; - IRDA_TASK_CALLBACK function; - IRDA_TASK_CALLBACK finished; - - struct irda_task *parent; - struct timer_list timer; - - void *instance; /* Instance being called */ - void *param; /* Parameter to be used by instance */ -}; - -/* Dongle info */ -struct dongle_reg; -typedef struct { - struct dongle_reg *issue; /* Registration info */ - struct net_device *dev; /* Device we are attached to */ - struct irda_task *speed_task; /* Task handling speed change */ - struct irda_task *reset_task; /* Task handling reset */ - __u32 speed; /* Current speed */ - - /* Callbacks to the IrDA device driver */ - int (*set_mode)(struct net_device *, int mode); - int (*read)(struct net_device *dev, __u8 *buf, int len); - int (*write)(struct net_device *dev, __u8 *buf, int len); - int (*set_dtr_rts)(struct net_device *dev, int dtr, int rts); -} dongle_t; - -/* Dongle registration info */ -struct dongle_reg { - irda_queue_t q; /* Must be first */ - IRDA_DONGLE type; - - void (*open)(dongle_t *dongle, struct qos_info *qos); - void (*close)(dongle_t *dongle); - int (*reset)(struct irda_task *task); - int (*change_speed)(struct irda_task *task); - struct module *owner; -}; - -/* - * Per-packet information we need to hide inside sk_buff - * (must not exceed 48 bytes, check with struct sk_buff) - * The default_qdisc_pad field is a temporary hack. - */ -struct irda_skb_cb { - unsigned int default_qdisc_pad; - magic_t magic; /* Be sure that we can trust the information */ - __u32 next_speed; /* The Speed to be set *after* this frame */ - __u16 mtt; /* Minimum turn around time */ - __u16 xbofs; /* Number of xbofs required, used by SIR mode */ - __u16 next_xbofs; /* Number of xbofs required *after* this frame */ - void *context; /* May be used by drivers */ - void (*destructor)(struct sk_buff *skb); /* Used for flow control */ - __u16 xbofs_delay; /* Number of xbofs used for generating the mtt */ - __u8 line; /* Used by IrCOMM in IrLPT mode */ -}; - -/* Chip specific info */ -typedef struct { - int cfg_base; /* Config register IO base */ - int sir_base; /* SIR IO base */ - int fir_base; /* FIR IO base */ - int mem_base; /* Shared memory base */ - int sir_ext; /* Length of SIR iobase */ - int fir_ext; /* Length of FIR iobase */ - int irq, irq2; /* Interrupts used */ - int dma, dma2; /* DMA channel(s) used */ - int fifo_size; /* FIFO size */ - int irqflags; /* interrupt flags (ie, IRQF_SHARED) */ - int direction; /* Link direction, used by some FIR drivers */ - int enabled; /* Powered on? */ - int suspended; /* Suspended by APM */ - __u32 speed; /* Currently used speed */ - __u32 new_speed; /* Speed we must change to when Tx is finished */ - int dongle_id; /* Dongle or transceiver currently used */ -} chipio_t; - -/* IO buffer specific info (inspired by struct sk_buff) */ -typedef struct { - int state; /* Receiving state (transmit state not used) */ - int in_frame; /* True if receiving frame */ - - __u8 *head; /* start of buffer */ - __u8 *data; /* start of data in buffer */ - - int len; /* current length of data */ - int truesize; /* total allocated size of buffer */ - __u16 fcs; - - struct sk_buff *skb; /* ZeroCopy Rx in async_unwrap_char() */ -} iobuff_t; - -/* Maximum SIR frame (skb) that we expect to receive *unwrapped*. - * Max LAP MTU (I field) is 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40). - * Max LAP header is 2 bytes (for now). - * Max CRC is 2 bytes at SIR, 4 bytes at FIR. - * Need 1 byte for skb_reserve() to align IP header for IrLAN. - * Add a few extra bytes just to be safe (buffer is power of two anyway) - * Jean II */ -#define IRDA_SKB_MAX_MTU 2064 -/* Maximum SIR frame that we expect to send, wrapped (i.e. with XBOFS - * and escaped characters on top of above). */ -#define IRDA_SIR_MAX_FRAME 4269 - -/* The SIR unwrapper async_unwrap_char() will use a Rx-copy-break mechanism - * when using the optional ZeroCopy Rx, where only small frames are memcpy - * to a smaller skb to save memory. This is the threshold under which copy - * will happen (and over which it won't happen). - * Some FIR drivers may use this #define as well... - * This is the same value as various Ethernet drivers. - Jean II */ -#define IRDA_RX_COPY_THRESHOLD 256 - -/* Function prototypes */ -int irda_device_init(void); -void irda_device_cleanup(void); - -/* IrLAP entry points used by the drivers. - * We declare them here to avoid the driver pulling a whole bunch stack - * headers they don't really need - Jean II */ -struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, - const char *hw_name); -void irlap_close(struct irlap_cb *self); - -/* Interface to be uses by IrLAP */ -void irda_device_set_media_busy(struct net_device *dev, int status); -int irda_device_is_media_busy(struct net_device *dev); -int irda_device_is_receiving(struct net_device *dev); - -/* Interface for internal use */ -static inline int irda_device_txqueue_empty(const struct net_device *dev) -{ - return qdisc_all_tx_empty(dev); -} -int irda_device_set_raw_mode(struct net_device* self, int status); -struct net_device *alloc_irdadev(int sizeof_priv); - -void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode); - -/* - * Function irda_get_mtt (skb) - * - * Utility function for getting the minimum turnaround time out of - * the skb, where it has been hidden in the cb field. - */ -static inline __u16 irda_get_mtt(const struct sk_buff *skb) -{ - const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; - return (cb->magic == LAP_MAGIC) ? cb->mtt : 10000; -} - -/* - * Function irda_get_next_speed (skb) - * - * Extract the speed that should be set *after* this frame from the skb - * - * Note : return -1 for user space frames - */ -static inline __u32 irda_get_next_speed(const struct sk_buff *skb) -{ - const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; - return (cb->magic == LAP_MAGIC) ? cb->next_speed : -1; -} - -/* - * Function irda_get_next_xbofs (skb) - * - * Extract the xbofs that should be set for this frame from the skb - * - * Note : default to 10 for user space frames - */ -static inline __u16 irda_get_xbofs(const struct sk_buff *skb) -{ - const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; - return (cb->magic == LAP_MAGIC) ? cb->xbofs : 10; -} - -/* - * Function irda_get_next_xbofs (skb) - * - * Extract the xbofs that should be set *after* this frame from the skb - * - * Note : return -1 for user space frames - */ -static inline __u16 irda_get_next_xbofs(const struct sk_buff *skb) -{ - const struct irda_skb_cb *cb = (const struct irda_skb_cb *) skb->cb; - return (cb->magic == LAP_MAGIC) ? cb->next_xbofs : -1; -} -#endif /* IRDA_DEVICE_H */ - - diff --git a/drivers/staging/irda/include/net/irda/iriap.h b/drivers/staging/irda/include/net/irda/iriap.h deleted file mode 100644 index fcc896491a95..000000000000 --- a/drivers/staging/irda/include/net/irda/iriap.h +++ /dev/null @@ -1,108 +0,0 @@ -/********************************************************************* - * - * Filename: iriap.h - * Version: 0.5 - * Description: Information Access Protocol (IAP) - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Aug 21 00:02:07 1997 - * Modified at: Sat Dec 25 16:42:09 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRIAP_H -#define IRIAP_H - -#include <linux/types.h> -#include <linux/skbuff.h> - -#include <net/irda/iriap_event.h> -#include <net/irda/irias_object.h> -#include <net/irda/irqueue.h> /* irda_queue_t */ -#include <net/irda/timer.h> /* struct timer_list */ - -#define IAP_LST 0x80 -#define IAP_ACK 0x40 - -#define IAS_SERVER 0 -#define IAS_CLIENT 1 - -/* IrIAP Op-codes */ -#define GET_INFO_BASE 0x01 -#define GET_OBJECTS 0x02 -#define GET_VALUE 0x03 -#define GET_VALUE_BY_CLASS 0x04 -#define GET_OBJECT_INFO 0x05 -#define GET_ATTRIB_NAMES 0x06 - -#define IAS_SUCCESS 0 -#define IAS_CLASS_UNKNOWN 1 -#define IAS_ATTRIB_UNKNOWN 2 -#define IAS_DISCONNECT 10 - -typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id, - struct ias_value *value, void *priv); - -struct iriap_cb { - irda_queue_t q; /* Must be first */ - magic_t magic; /* Magic cookie */ - - int mode; /* Client or server */ - - __u32 saddr; - __u32 daddr; - __u8 operation; - - struct sk_buff *request_skb; - struct lsap_cb *lsap; - __u8 slsap_sel; - - /* Client states */ - IRIAP_STATE client_state; - IRIAP_STATE call_state; - - /* Server states */ - IRIAP_STATE server_state; - IRIAP_STATE r_connect_state; - - CONFIRM_CALLBACK confirm; - void *priv; /* Used to identify client */ - - __u8 max_header_size; - __u32 max_data_size; - - struct timer_list watchdog_timer; -}; - -int iriap_init(void); -void iriap_cleanup(void); - -struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, - CONFIRM_CALLBACK callback); -void iriap_close(struct iriap_cb *self); - -int iriap_getvaluebyclass_request(struct iriap_cb *self, - __u32 saddr, __u32 daddr, - char *name, char *attr); -void iriap_connect_request(struct iriap_cb *self); -void iriap_send_ack( struct iriap_cb *self); -void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb); - -void iriap_register_server(void); - -#endif - - diff --git a/drivers/staging/irda/include/net/irda/iriap_event.h b/drivers/staging/irda/include/net/irda/iriap_event.h deleted file mode 100644 index 89747f06d9eb..000000000000 --- a/drivers/staging/irda/include/net/irda/iriap_event.h +++ /dev/null @@ -1,85 +0,0 @@ -/********************************************************************* - * - * Filename: iriap_event.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Sun Oct 31 22:02:54 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRIAP_FSM_H -#define IRIAP_FSM_H - -/* Forward because of circular include dependecies */ -struct iriap_cb; - -/* IrIAP states */ -typedef enum { - /* Client */ - S_DISCONNECT, - S_CONNECTING, - S_CALL, - - /* S-Call */ - S_MAKE_CALL, - S_CALLING, - S_OUTSTANDING, - S_REPLYING, - S_WAIT_FOR_CALL, - S_WAIT_ACTIVE, - - /* Server */ - R_DISCONNECT, - R_CALL, - - /* R-Connect */ - R_WAITING, - R_WAIT_ACTIVE, - R_RECEIVING, - R_EXECUTE, - R_RETURNING, -} IRIAP_STATE; - -typedef enum { - IAP_CALL_REQUEST, - IAP_CALL_REQUEST_GVBC, - IAP_CALL_RESPONSE, - IAP_RECV_F_LST, - IAP_LM_DISCONNECT_INDICATION, - IAP_LM_CONNECT_INDICATION, - IAP_LM_CONNECT_CONFIRM, -} IRIAP_EVENT; - -void iriap_next_client_state (struct iriap_cb *self, IRIAP_STATE state); -void iriap_next_call_state (struct iriap_cb *self, IRIAP_STATE state); -void iriap_next_server_state (struct iriap_cb *self, IRIAP_STATE state); -void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state); - - -void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -void iriap_do_call_event (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); - -void iriap_do_server_event (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); - -#endif /* IRIAP_FSM_H */ - diff --git a/drivers/staging/irda/include/net/irda/irias_object.h b/drivers/staging/irda/include/net/irda/irias_object.h deleted file mode 100644 index 83f78081799c..000000000000 --- a/drivers/staging/irda/include/net/irda/irias_object.h +++ /dev/null @@ -1,108 +0,0 @@ -/********************************************************************* - * - * Filename: irias_object.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Oct 1 22:49:50 1998 - * Modified at: Wed Dec 15 11:20:57 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef LM_IAS_OBJECT_H -#define LM_IAS_OBJECT_H - -#include <net/irda/irda.h> -#include <net/irda/irqueue.h> - -/* LM-IAS Attribute types */ -#define IAS_MISSING 0 -#define IAS_INTEGER 1 -#define IAS_OCT_SEQ 2 -#define IAS_STRING 3 - -/* Object ownership of attributes (user or kernel) */ -#define IAS_KERNEL_ATTR 0 -#define IAS_USER_ATTR 1 - -/* - * LM-IAS Object - */ -struct ias_object { - irda_queue_t q; /* Must be first! */ - magic_t magic; - - char *name; - int id; - hashbin_t *attribs; -}; - -/* - * Values used by LM-IAS attributes - */ -struct ias_value { - __u8 type; /* Value description */ - __u8 owner; /* Managed from user/kernel space */ - int charset; /* Only used by string type */ - int len; - - /* Value */ - union { - int integer; - char *string; - __u8 *oct_seq; - } t; -}; - -/* - * Attributes used by LM-IAS objects - */ -struct ias_attrib { - irda_queue_t q; /* Must be first! */ - int magic; - - char *name; /* Attribute name */ - struct ias_value *value; /* Attribute value */ -}; - -struct ias_object *irias_new_object(char *name, int id); -void irias_insert_object(struct ias_object *obj); -int irias_delete_object(struct ias_object *obj); -int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib, - int cleanobject); -void __irias_delete_object(struct ias_object *obj); - -void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, - int user); -void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, - int user); -void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, - int len, int user); -int irias_object_change_attribute(char *obj_name, char *attrib_name, - struct ias_value *new_value); -struct ias_object *irias_find_object(char *name); -struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name); - -struct ias_value *irias_new_string_value(char *string); -struct ias_value *irias_new_integer_value(int integer); -struct ias_value *irias_new_octseq_value(__u8 *octseq , int len); -struct ias_value *irias_new_missing_value(void); -void irias_delete_value(struct ias_value *value); - -extern struct ias_value irias_missing; -extern hashbin_t *irias_objects; - -#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_client.h b/drivers/staging/irda/include/net/irda/irlan_client.h deleted file mode 100644 index fa8455eda280..000000000000 --- a/drivers/staging/irda/include/net/irda/irlan_client.h +++ /dev/null @@ -1,42 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_client.h - * Version: 0.3 - * Description: IrDA LAN access layer - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Thu Apr 22 14:13:34 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAN_CLIENT_H -#define IRLAN_CLIENT_H - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> - -#include <net/irda/irias_object.h> -#include <net/irda/irlan_event.h> - -void irlan_client_discovery_indication(discinfo_t *, DISCOVERY_MODE, void *); -void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr); - -void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb); -void irlan_client_get_value_confirm(int result, __u16 obj_id, - struct ias_value *value, void *priv); -#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_common.h b/drivers/staging/irda/include/net/irda/irlan_common.h deleted file mode 100644 index 550c2d6ec7ff..000000000000 --- a/drivers/staging/irda/include/net/irda/irlan_common.h +++ /dev/null @@ -1,230 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_common.h - * Version: 0.8 - * Description: IrDA LAN access layer - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Sun Oct 31 19:41:24 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAN_H -#define IRLAN_H - -#include <asm/param.h> /* for HZ */ - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/if_ether.h> - -#include <net/irda/irttp.h> - -#define IRLAN_MTU 1518 -#define IRLAN_TIMEOUT 10*HZ /* 10 seconds */ - -/* Command packet types */ -#define CMD_GET_PROVIDER_INFO 0 -#define CMD_GET_MEDIA_CHAR 1 -#define CMD_OPEN_DATA_CHANNEL 2 -#define CMD_CLOSE_DATA_CHAN 3 -#define CMD_RECONNECT_DATA_CHAN 4 -#define CMD_FILTER_OPERATION 5 - -/* Some responses */ -#define RSP_SUCCESS 0 -#define RSP_INSUFFICIENT_RESOURCES 1 -#define RSP_INVALID_COMMAND_FORMAT 2 -#define RSP_COMMAND_NOT_SUPPORTED 3 -#define RSP_PARAM_NOT_SUPPORTED 4 -#define RSP_VALUE_NOT_SUPPORTED 5 -#define RSP_NOT_OPEN 6 -#define RSP_AUTHENTICATION_REQUIRED 7 -#define RSP_INVALID_PASSWORD 8 -#define RSP_PROTOCOL_ERROR 9 -#define RSP_ASYNCHRONOUS_ERROR 255 - -/* Media types */ -#define MEDIA_802_3 1 -#define MEDIA_802_5 2 - -/* Filter parameters */ -#define DATA_CHAN 1 -#define FILTER_TYPE 2 -#define FILTER_MODE 3 - -/* Filter types */ -#define IRLAN_DIRECTED 0x01 -#define IRLAN_FUNCTIONAL 0x02 -#define IRLAN_GROUP 0x04 -#define IRLAN_MAC_FRAME 0x08 -#define IRLAN_MULTICAST 0x10 -#define IRLAN_BROADCAST 0x20 -#define IRLAN_IPX_SOCKET 0x40 - -/* Filter modes */ -#define ALL 1 -#define FILTER 2 -#define NONE 3 - -/* Filter operations */ -#define GET 1 -#define CLEAR 2 -#define ADD 3 -#define REMOVE 4 -#define DYNAMIC 5 - -/* Access types */ -#define ACCESS_DIRECT 1 -#define ACCESS_PEER 2 -#define ACCESS_HOSTED 3 - -#define IRLAN_BYTE 0 -#define IRLAN_SHORT 1 -#define IRLAN_ARRAY 2 - -/* IrLAN sits on top if IrTTP */ -#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER) -/* 1 byte for the command code and 1 byte for the parameter count */ -#define IRLAN_CMD_HEADER 2 - -#define IRLAN_STRING_PARAMETER_LEN(name, value) (1 + strlen((name)) + 2 \ - + strlen ((value))) -#define IRLAN_BYTE_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 1) -#define IRLAN_SHORT_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 2) - -/* - * IrLAN client - */ -struct irlan_client_cb { - int state; - - int open_retries; - - struct tsap_cb *tsap_ctrl; - __u32 max_sdu_size; - __u8 max_header_size; - - int access_type; /* Access type of provider */ - __u8 reconnect_key[255]; - __u8 key_len; - - __u16 recv_arb_val; - __u16 max_frame; - int filter_type; - - int unicast_open; - int broadcast_open; - - int tx_busy; - struct sk_buff_head txq; /* Transmit control queue */ - - struct iriap_cb *iriap; - - struct timer_list kick_timer; -}; - -/* - * IrLAN provider - */ -struct irlan_provider_cb { - int state; - - struct tsap_cb *tsap_ctrl; - __u32 max_sdu_size; - __u8 max_header_size; - - /* - * Store some values here which are used by the provider to parse - * the filter operations - */ - int data_chan; - int filter_type; - int filter_mode; - int filter_operation; - int filter_entry; - int access_type; /* Access type */ - __u16 send_arb_val; - - __u8 mac_address[ETH_ALEN]; /* Generated MAC address for peer device */ -}; - -/* - * IrLAN control block - */ -struct irlan_cb { - int magic; - struct list_head dev_list; - struct net_device *dev; /* Ethernet device structure*/ - - __u32 saddr; /* Source device address */ - __u32 daddr; /* Destination device address */ - int disconnect_reason; /* Why we got disconnected */ - - int media; /* Media type */ - __u8 version[2]; /* IrLAN version */ - - struct tsap_cb *tsap_data; /* Data TSAP */ - - int use_udata; /* Use Unit Data transfers */ - - __u8 stsap_sel_data; /* Source data TSAP selector */ - __u8 dtsap_sel_data; /* Destination data TSAP selector */ - __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */ - - struct irlan_client_cb client; /* Client specific fields */ - struct irlan_provider_cb provider; /* Provider specific fields */ - - __u32 max_sdu_size; - __u8 max_header_size; - - wait_queue_head_t open_wait; - struct timer_list watchdog_timer; -}; - -void irlan_close(struct irlan_cb *self); -void irlan_close_tsaps(struct irlan_cb *self); - -int irlan_register_netdev(struct irlan_cb *self); -void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel); -void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout); - -void irlan_open_data_tsap(struct irlan_cb *self); - -int irlan_run_ctrl_tx_queue(struct irlan_cb *self); - -struct irlan_cb *irlan_get_any(void); -void irlan_get_provider_info(struct irlan_cb *self); -void irlan_get_media_char(struct irlan_cb *self); -void irlan_open_data_channel(struct irlan_cb *self); -void irlan_close_data_channel(struct irlan_cb *self); -void irlan_set_multicast_filter(struct irlan_cb *self, int status); -void irlan_set_broadcast_filter(struct irlan_cb *self, int status); - -int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value); -int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value); -int irlan_insert_string_param(struct sk_buff *skb, char *param, char *value); -int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *value, - __u16 value_len); - -int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len); - -#endif - - diff --git a/drivers/staging/irda/include/net/irda/irlan_eth.h b/drivers/staging/irda/include/net/irda/irlan_eth.h deleted file mode 100644 index de5c81691f33..000000000000 --- a/drivers/staging/irda/include/net/irda/irlan_eth.h +++ /dev/null @@ -1,32 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_eth.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Oct 15 08:36:58 1998 - * Modified at: Fri May 14 23:29:00 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAN_ETH_H -#define IRLAN_ETH_H - -struct net_device *alloc_irlandev(const char *name); -int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb); - -void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow); -#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_event.h b/drivers/staging/irda/include/net/irda/irlan_event.h deleted file mode 100644 index 018b5a77e610..000000000000 --- a/drivers/staging/irda/include/net/irda/irlan_event.h +++ /dev/null @@ -1,81 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_event.h - * Version: - * Description: LAN access - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Tue Feb 2 09:45:17 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAN_EVENT_H -#define IRLAN_EVENT_H - -#include <linux/kernel.h> -#include <linux/skbuff.h> - -#include <net/irda/irlan_common.h> - -typedef enum { - IRLAN_IDLE, - IRLAN_QUERY, - IRLAN_CONN, - IRLAN_INFO, - IRLAN_MEDIA, - IRLAN_OPEN, - IRLAN_WAIT, - IRLAN_ARB, - IRLAN_DATA, - IRLAN_CLOSE, - IRLAN_SYNC -} IRLAN_STATE; - -typedef enum { - IRLAN_DISCOVERY_INDICATION, - IRLAN_IAS_PROVIDER_AVAIL, - IRLAN_IAS_PROVIDER_NOT_AVAIL, - IRLAN_LAP_DISCONNECT, - IRLAN_LMP_DISCONNECT, - IRLAN_CONNECT_COMPLETE, - IRLAN_DATA_INDICATION, - IRLAN_DATA_CONNECT_INDICATION, - IRLAN_RETRY_CONNECT, - - IRLAN_CONNECT_INDICATION, - IRLAN_GET_INFO_CMD, - IRLAN_GET_MEDIA_CMD, - IRLAN_OPEN_DATA_CMD, - IRLAN_FILTER_CONFIG_CMD, - - IRLAN_CHECK_CON_ARB, - IRLAN_PROVIDER_SIGNAL, - - IRLAN_WATCHDOG_TIMEOUT, -} IRLAN_EVENT; - -extern const char * const irlan_state[]; - -void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); - -void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); - -void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state); -void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state); - -#endif diff --git a/drivers/staging/irda/include/net/irda/irlan_filter.h b/drivers/staging/irda/include/net/irda/irlan_filter.h deleted file mode 100644 index a5a2539485bd..000000000000 --- a/drivers/staging/irda/include/net/irda/irlan_filter.h +++ /dev/null @@ -1,35 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_filter.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri Jan 29 15:24:08 1999 - * Modified at: Sun Feb 7 23:35:31 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAN_FILTER_H -#define IRLAN_FILTER_H - -void irlan_check_command_param(struct irlan_cb *self, char *param, - char *value); -void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb); -#ifdef CONFIG_PROC_FS -void irlan_print_filter(struct seq_file *seq, int filter_type); -#endif - -#endif /* IRLAN_FILTER_H */ diff --git a/drivers/staging/irda/include/net/irda/irlan_provider.h b/drivers/staging/irda/include/net/irda/irlan_provider.h deleted file mode 100644 index 92f3b0e1029b..000000000000 --- a/drivers/staging/irda/include/net/irda/irlan_provider.h +++ /dev/null @@ -1,52 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_provider.h - * Version: 0.1 - * Description: IrDA LAN access layer - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Sun May 9 12:26:11 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAN_SERVER_H -#define IRLAN_SERVER_H - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> - -#include <net/irda/irlan_common.h> - -void irlan_provider_ctrl_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *skb); - - -void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *); - -int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb); -int irlan_provider_parse_command(struct irlan_cb *self, int cmd, - struct sk_buff *skb); - -void irlan_provider_send_reply(struct irlan_cb *self, int command, - int ret_code); -int irlan_provider_open_ctrl_tsap(struct irlan_cb *self); - -#endif - - diff --git a/drivers/staging/irda/include/net/irda/irlap.h b/drivers/staging/irda/include/net/irda/irlap.h deleted file mode 100644 index 6f23e820618c..000000000000 --- a/drivers/staging/irda/include/net/irda/irlap.h +++ /dev/null @@ -1,311 +0,0 @@ -/********************************************************************* - * - * Filename: irlap.h - * Version: 0.8 - * Description: An IrDA LAP driver for Linux - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Fri Dec 10 13:21:17 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLAP_H -#define IRLAP_H - -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/timer.h> - -#include <net/irda/irqueue.h> /* irda_queue_t */ -#include <net/irda/qos.h> /* struct qos_info */ -#include <net/irda/discovery.h> /* discovery_t */ -#include <net/irda/irlap_event.h> /* IRLAP_STATE, ... */ -#include <net/irda/irmod.h> /* struct notify_t */ - -#define CONFIG_IRDA_DYNAMIC_WINDOW 1 - -#define LAP_RELIABLE 1 -#define LAP_UNRELIABLE 0 - -#define LAP_ADDR_HEADER 1 /* IrLAP Address Header */ -#define LAP_CTRL_HEADER 1 /* IrLAP Control Header */ - -/* May be different when we get VFIR */ -#define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER) - -/* Each IrDA device gets a random 32 bits IRLAP device address */ -#define LAP_ALEN 4 - -#define BROADCAST 0xffffffff /* Broadcast device address */ -#define CBROADCAST 0xfe /* Connection broadcast address */ -#define XID_FORMAT 0x01 /* Discovery XID format */ - -/* Nobody seems to use this constant. */ -#define LAP_WINDOW_SIZE 8 -/* We keep the LAP queue very small to minimise the amount of buffering. - * this improve latency and reduce resource consumption. - * This work only because we have synchronous refilling of IrLAP through - * the flow control mechanism (via scheduler and IrTTP). - * 2 buffers is the minimum we can work with, one that we send while polling - * IrTTP, and another to know that we should not send the pf bit. - * Jean II */ -#define LAP_HIGH_THRESHOLD 2 -/* Some rare non TTP clients don't implement flow control, and - * so don't comply with the above limit (and neither with this one). - * For IAP and management, it doesn't matter, because they never transmit much. - *.For IrLPT, this should be fixed. - * - Jean II */ -#define LAP_MAX_QUEUE 10 -/* Please note that all IrDA management frames (LMP/TTP conn req/disc and - * IAS queries) fall in the second category and are sent to LAP even if TTP - * is stopped. This means that those frames will wait only a maximum of - * two (2) data frames before beeing sent on the "wire", which speed up - * new socket setup when the link is saturated. - * Same story for two sockets competing for the medium : if one saturates - * the LAP, when the other want to transmit it only has to wait for - * maximum three (3) packets (2 + one scheduling), which improve performance - * of delay sensitive applications. - * Jean II */ - -#define NR_EXPECTED 1 -#define NR_UNEXPECTED 0 -#define NR_INVALID -1 - -#define NS_EXPECTED 1 -#define NS_UNEXPECTED 0 -#define NS_INVALID -1 - -/* - * Meta information passed within the IrLAP state machine - */ -struct irlap_info { - __u8 caddr; /* Connection address */ - __u8 control; /* Frame type */ - __u8 cmd; - - __u32 saddr; - __u32 daddr; - - int pf; /* Poll/final bit set */ - - __u8 nr; /* Sequence number of next frame expected */ - __u8 ns; /* Sequence number of frame sent */ - - int S; /* Number of slots */ - int slot; /* Random chosen slot */ - int s; /* Current slot */ - - discovery_t *discovery; /* Discovery information */ -}; - -/* Main structure of IrLAP */ -struct irlap_cb { - irda_queue_t q; /* Must be first */ - magic_t magic; - - /* Device we are attached to */ - struct net_device *netdev; - char hw_name[2*IFNAMSIZ + 1]; - - /* Connection state */ - volatile IRLAP_STATE state; /* Current state */ - - /* Timers used by IrLAP */ - struct timer_list query_timer; - struct timer_list slot_timer; - struct timer_list discovery_timer; - struct timer_list final_timer; - struct timer_list poll_timer; - struct timer_list wd_timer; - struct timer_list backoff_timer; - - /* Media busy stuff */ - struct timer_list media_busy_timer; - int media_busy; - - /* Timeouts which will be different with different turn time */ - int slot_timeout; - int poll_timeout; - int final_timeout; - int wd_timeout; - - struct sk_buff_head txq; /* Frames to be transmitted */ - struct sk_buff_head txq_ultra; - - __u8 caddr; /* Connection address */ - __u32 saddr; /* Source device address */ - __u32 daddr; /* Destination device address */ - - int retry_count; /* Times tried to establish connection */ - int add_wait; /* True if we are waiting for frame */ - - __u8 connect_pending; - __u8 disconnect_pending; - - /* To send a faster RR if tx queue empty */ -#ifdef CONFIG_IRDA_FAST_RR - int fast_RR_timeout; - int fast_RR; -#endif /* CONFIG_IRDA_FAST_RR */ - - int N1; /* N1 * F-timer = Negitiated link disconnect warning threshold */ - int N2; /* N2 * F-timer = Negitiated link disconnect time */ - int N3; /* Connection retry count */ - - int local_busy; - int remote_busy; - int xmitflag; - - __u8 vs; /* Next frame to be sent */ - __u8 vr; /* Next frame to be received */ - __u8 va; /* Last frame acked */ - int window; /* Nr of I-frames allowed to send */ - int window_size; /* Current negotiated window size */ - -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - __u32 line_capacity; /* Number of bytes allowed to send */ - __u32 bytes_left; /* Number of bytes still allowed to transmit */ -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - - struct sk_buff_head wx_list; - - __u8 ack_required; - - /* XID parameters */ - __u8 S; /* Number of slots */ - __u8 slot; /* Random chosen slot */ - __u8 s; /* Current slot */ - int frame_sent; /* Have we sent reply? */ - - hashbin_t *discovery_log; - discovery_t *discovery_cmd; - - __u32 speed; /* Link speed */ - - struct qos_info qos_tx; /* QoS requested by peer */ - struct qos_info qos_rx; /* QoS requested by self */ - struct qos_info *qos_dev; /* QoS supported by device */ - - notify_t notify; /* Callbacks to IrLMP */ - - int mtt_required; /* Minimum turnaround time required */ - int xbofs_delay; /* Nr of XBOF's used to MTT */ - int bofs_count; /* Negotiated extra BOFs */ - int next_bofs; /* Negotiated extra BOFs after next frame */ - - int mode; /* IrLAP mode (primary, secondary or monitor) */ -}; - -/* - * Function prototypes - */ -int irlap_init(void); -void irlap_cleanup(void); - -struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, - const char *hw_name); -void irlap_close(struct irlap_cb *self); - -void irlap_connect_request(struct irlap_cb *self, __u32 daddr, - struct qos_info *qos, int sniff); -void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb); -void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb); -void irlap_connect_confirm(struct irlap_cb *, struct sk_buff *skb); - -void irlap_data_indication(struct irlap_cb *, struct sk_buff *, int unreliable); -void irlap_data_request(struct irlap_cb *, struct sk_buff *, int unreliable); - -#ifdef CONFIG_IRDA_ULTRA -void irlap_unitdata_request(struct irlap_cb *, struct sk_buff *); -void irlap_unitdata_indication(struct irlap_cb *, struct sk_buff *); -#endif /* CONFIG_IRDA_ULTRA */ - -void irlap_disconnect_request(struct irlap_cb *); -void irlap_disconnect_indication(struct irlap_cb *, LAP_REASON reason); - -void irlap_status_indication(struct irlap_cb *, int quality_of_link); - -void irlap_test_request(__u8 *info, int len); - -void irlap_discovery_request(struct irlap_cb *, discovery_t *discovery); -void irlap_discovery_confirm(struct irlap_cb *, hashbin_t *discovery_log); -void irlap_discovery_indication(struct irlap_cb *, discovery_t *discovery); - -void irlap_reset_indication(struct irlap_cb *self); -void irlap_reset_confirm(void); - -void irlap_update_nr_received(struct irlap_cb *, int nr); -int irlap_validate_nr_received(struct irlap_cb *, int nr); -int irlap_validate_ns_received(struct irlap_cb *, int ns); - -int irlap_generate_rand_time_slot(int S, int s); -void irlap_initiate_connection_state(struct irlap_cb *); -void irlap_flush_all_queues(struct irlap_cb *); -void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *); - -void irlap_apply_default_connection_parameters(struct irlap_cb *self); -void irlap_apply_connection_parameters(struct irlap_cb *self, int now); - -#define IRLAP_GET_HEADER_SIZE(self) (LAP_MAX_HEADER) -#define IRLAP_GET_TX_QUEUE_LEN(self) skb_queue_len(&self->txq) - -/* Return TRUE if the node is in primary mode (i.e. master) - * - Jean II */ -static inline int irlap_is_primary(struct irlap_cb *self) -{ - int ret; - switch(self->state) { - case LAP_XMIT_P: - case LAP_NRM_P: - ret = 1; - break; - case LAP_XMIT_S: - case LAP_NRM_S: - ret = 0; - break; - default: - ret = -1; - } - return ret; -} - -/* Clear a pending IrLAP disconnect. - Jean II */ -static inline void irlap_clear_disconnect(struct irlap_cb *self) -{ - self->disconnect_pending = FALSE; -} - -/* - * Function irlap_next_state (self, state) - * - * Switches state and provides debug information - * - */ -static inline void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) -{ - /* - if (!self || self->magic != LAP_MAGIC) - return; - - pr_debug("next LAP state = %s\n", irlap_state[state]); - */ - self->state = state; -} - -#endif diff --git a/drivers/staging/irda/include/net/irda/irlap_event.h b/drivers/staging/irda/include/net/irda/irlap_event.h deleted file mode 100644 index e4325fee1267..000000000000 --- a/drivers/staging/irda/include/net/irda/irlap_event.h +++ /dev/null @@ -1,129 +0,0 @@ -/********************************************************************* - * - * - * Filename: irlap_event.h - * Version: 0.1 - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Aug 16 00:59:29 1997 - * Modified at: Tue Dec 21 11:20:30 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRLAP_EVENT_H -#define IRLAP_EVENT_H - -#include <net/irda/irda.h> - -/* A few forward declarations (to make compiler happy) */ -struct irlap_cb; -struct irlap_info; - -/* IrLAP States */ -typedef enum { - LAP_NDM, /* Normal disconnected mode */ - LAP_QUERY, - LAP_REPLY, - LAP_CONN, /* Connect indication */ - LAP_SETUP, /* Setting up connection */ - LAP_OFFLINE, /* A really boring state */ - LAP_XMIT_P, - LAP_PCLOSE, - LAP_NRM_P, /* Normal response mode as primary */ - LAP_RESET_WAIT, - LAP_RESET, - LAP_NRM_S, /* Normal response mode as secondary */ - LAP_XMIT_S, - LAP_SCLOSE, - LAP_RESET_CHECK, -} IRLAP_STATE; - -/* IrLAP Events */ -typedef enum { - /* Services events */ - DISCOVERY_REQUEST, - CONNECT_REQUEST, - CONNECT_RESPONSE, - DISCONNECT_REQUEST, - DATA_REQUEST, - RESET_REQUEST, - RESET_RESPONSE, - - /* Send events */ - SEND_I_CMD, - SEND_UI_FRAME, - - /* Receive events */ - RECV_DISCOVERY_XID_CMD, - RECV_DISCOVERY_XID_RSP, - RECV_SNRM_CMD, - RECV_TEST_CMD, - RECV_TEST_RSP, - RECV_UA_RSP, - RECV_DM_RSP, - RECV_RD_RSP, - RECV_I_CMD, - RECV_I_RSP, - RECV_UI_FRAME, - RECV_FRMR_RSP, - RECV_RR_CMD, - RECV_RR_RSP, - RECV_RNR_CMD, - RECV_RNR_RSP, - RECV_REJ_CMD, - RECV_REJ_RSP, - RECV_SREJ_CMD, - RECV_SREJ_RSP, - RECV_DISC_CMD, - - /* Timer events */ - SLOT_TIMER_EXPIRED, - QUERY_TIMER_EXPIRED, - FINAL_TIMER_EXPIRED, - POLL_TIMER_EXPIRED, - DISCOVERY_TIMER_EXPIRED, - WD_TIMER_EXPIRED, - BACKOFF_TIMER_EXPIRED, - MEDIA_BUSY_TIMER_EXPIRED, -} IRLAP_EVENT; - -/* - * Disconnect reason code - */ -typedef enum { /* FIXME check the two first reason codes */ - LAP_DISC_INDICATION=1, /* Received a disconnect request from peer */ - LAP_NO_RESPONSE, /* To many retransmits without response */ - LAP_RESET_INDICATION, /* To many retransmits, or invalid nr/ns */ - LAP_FOUND_NONE, /* No devices were discovered */ - LAP_MEDIA_BUSY, - LAP_PRIMARY_CONFLICT, -} LAP_REASON; - -extern const char *const irlap_state[]; - -void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -void irlap_print_event(IRLAP_EVENT event); - -int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb); - -#endif diff --git a/drivers/staging/irda/include/net/irda/irlap_frame.h b/drivers/staging/irda/include/net/irda/irlap_frame.h deleted file mode 100644 index cbc12a926e5f..000000000000 --- a/drivers/staging/irda/include/net/irda/irlap_frame.h +++ /dev/null @@ -1,167 +0,0 @@ -/********************************************************************* - * - * Filename: irlap_frame.h - * Version: 0.9 - * Description: IrLAP frame declarations - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Aug 19 10:27:26 1997 - * Modified at: Sat Dec 25 21:07:26 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRLAP_FRAME_H -#define IRLAP_FRAME_H - -#include <linux/skbuff.h> - -#include <net/irda/irda.h> - -/* A few forward declarations (to make compiler happy) */ -struct irlap_cb; -struct discovery_t; - -/* Frame types and templates */ -#define INVALID 0xff - -/* Unnumbered (U) commands */ -#define SNRM_CMD 0x83 /* Set Normal Response Mode */ -#define DISC_CMD 0x43 /* Disconnect */ -#define XID_CMD 0x2f /* Exchange Station Identification */ -#define TEST_CMD 0xe3 /* Test */ - -/* Unnumbered responses */ -#define RNRM_RSP 0x83 /* Request Normal Response Mode */ -#define UA_RSP 0x63 /* Unnumbered Acknowledgement */ -#define FRMR_RSP 0x87 /* Frame Reject */ -#define DM_RSP 0x0f /* Disconnect Mode */ -#define RD_RSP 0x43 /* Request Disconnection */ -#define XID_RSP 0xaf /* Exchange Station Identification */ -#define TEST_RSP 0xe3 /* Test frame */ - -/* Supervisory (S) */ -#define RR 0x01 /* Receive Ready */ -#define REJ 0x09 /* Reject */ -#define RNR 0x05 /* Receive Not Ready */ -#define SREJ 0x0d /* Selective Reject */ - -/* Information (I) */ -#define I_FRAME 0x00 /* Information Format */ -#define UI_FRAME 0x03 /* Unnumbered Information */ - -#define CMD_FRAME 0x01 -#define RSP_FRAME 0x00 - -#define PF_BIT 0x10 /* Poll/final bit */ - -/* Some IrLAP field lengths */ -/* - * Only baud rate triplet is 4 bytes (PV can be 2 bytes). - * All others params (7) are 3 bytes, so that's 7*3 + 1*4 bytes. - */ -#define IRLAP_NEGOCIATION_PARAMS_LEN 25 -#define IRLAP_DISCOVERY_INFO_LEN 32 - -struct disc_frame { - __u8 caddr; /* Connection address */ - __u8 control; -} __packed; - -struct xid_frame { - __u8 caddr; /* Connection address */ - __u8 control; - __u8 ident; /* Should always be XID_FORMAT */ - __le32 saddr; /* Source device address */ - __le32 daddr; /* Destination device address */ - __u8 flags; /* Discovery flags */ - __u8 slotnr; - __u8 version; -} __packed; - -struct test_frame { - __u8 caddr; /* Connection address */ - __u8 control; - __le32 saddr; /* Source device address */ - __le32 daddr; /* Destination device address */ -} __packed; - -struct ua_frame { - __u8 caddr; - __u8 control; - __le32 saddr; /* Source device address */ - __le32 daddr; /* Dest device address */ -} __packed; - -struct dm_frame { - __u8 caddr; /* Connection address */ - __u8 control; -} __packed; - -struct rd_frame { - __u8 caddr; /* Connection address */ - __u8 control; -} __packed; - -struct rr_frame { - __u8 caddr; /* Connection address */ - __u8 control; -} __packed; - -struct i_frame { - __u8 caddr; - __u8 control; -} __packed; - -struct snrm_frame { - __u8 caddr; - __u8 control; - __le32 saddr; - __le32 daddr; - __u8 ncaddr; -} __packed; - -void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb); -void irlap_send_discovery_xid_frame(struct irlap_cb *, int S, __u8 s, - __u8 command, - struct discovery_t *discovery); -void irlap_send_snrm_frame(struct irlap_cb *, struct qos_info *); -void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, - struct sk_buff *cmd); -void irlap_send_ua_response_frame(struct irlap_cb *, struct qos_info *); -void irlap_send_dm_frame(struct irlap_cb *self); -void irlap_send_rd_frame(struct irlap_cb *self); -void irlap_send_disc_frame(struct irlap_cb *self); -void irlap_send_rr_frame(struct irlap_cb *self, int command); - -void irlap_send_data_primary(struct irlap_cb *, struct sk_buff *); -void irlap_send_data_primary_poll(struct irlap_cb *, struct sk_buff *); -void irlap_send_data_secondary(struct irlap_cb *, struct sk_buff *); -void irlap_send_data_secondary_final(struct irlap_cb *, struct sk_buff *); -void irlap_resend_rejected_frames(struct irlap_cb *, int command); -void irlap_resend_rejected_frame(struct irlap_cb *self, int command); - -void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, - __u8 caddr, int command); - -int irlap_insert_qos_negotiation_params(struct irlap_cb *self, - struct sk_buff *skb); - -#endif diff --git a/drivers/staging/irda/include/net/irda/irlmp.h b/drivers/staging/irda/include/net/irda/irlmp.h deleted file mode 100644 index f132924cc9da..000000000000 --- a/drivers/staging/irda/include/net/irda/irlmp.h +++ /dev/null @@ -1,295 +0,0 @@ -/********************************************************************* - * - * Filename: irlmp.h - * Version: 0.9 - * Description: IrDA Link Management Protocol (LMP) layer - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 17 20:54:32 1997 - * Modified at: Fri Dec 10 13:23:01 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLMP_H -#define IRLMP_H - -#include <asm/param.h> /* for HZ */ - -#include <linux/types.h> - -#include <net/irda/irda.h> -#include <net/irda/qos.h> -#include <net/irda/irlap.h> /* LAP_MAX_HEADER, ... */ -#include <net/irda/irlmp_event.h> -#include <net/irda/irqueue.h> -#include <net/irda/discovery.h> - -/* LSAP-SEL's */ -#define LSAP_MASK 0x7f -#define LSAP_IAS 0x00 -#define LSAP_ANY 0xff -#define LSAP_MAX 0x6f /* 0x70-0x7f are reserved */ -#define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */ - -#define DEV_ADDR_ANY 0xffffffff - -#define LMP_HEADER 2 /* Dest LSAP + Source LSAP */ -#define LMP_CONTROL_HEADER 4 /* LMP_HEADER + opcode + parameter */ -#define LMP_PID_HEADER 1 /* Used by Ultra */ -#define LMP_MAX_HEADER (LMP_CONTROL_HEADER+LAP_MAX_HEADER) - -#define LM_MAX_CONNECTIONS 10 - -#define LM_IDLE_TIMEOUT 2*HZ /* 2 seconds for now */ - -typedef enum { - S_PNP = 0, - S_PDA, - S_COMPUTER, - S_PRINTER, - S_MODEM, - S_FAX, - S_LAN, - S_TELEPHONY, - S_COMM, - S_OBEX, - S_ANY, - S_END, -} SERVICE; - -/* For selective discovery */ -typedef void (*DISCOVERY_CALLBACK1) (discinfo_t *, DISCOVERY_MODE, void *); -/* For expiry (the same) */ -typedef void (*DISCOVERY_CALLBACK2) (discinfo_t *, DISCOVERY_MODE, void *); - -typedef struct { - irda_queue_t queue; /* Must be first */ - - __u16_host_order hints; /* Hint bits */ -} irlmp_service_t; - -typedef struct { - irda_queue_t queue; /* Must be first */ - - __u16_host_order hint_mask; - - DISCOVERY_CALLBACK1 disco_callback; /* Selective discovery */ - DISCOVERY_CALLBACK2 expir_callback; /* Selective expiration */ - void *priv; /* Used to identify client */ -} irlmp_client_t; - -/* - * Information about each logical LSAP connection - */ -struct lsap_cb { - irda_queue_t queue; /* Must be first */ - magic_t magic; - - unsigned long connected; /* set_bit used on this */ - int persistent; - - __u8 slsap_sel; /* Source (this) LSAP address */ - __u8 dlsap_sel; /* Destination LSAP address (if connected) */ -#ifdef CONFIG_IRDA_ULTRA - __u8 pid; /* Used by connectionless LSAP */ -#endif /* CONFIG_IRDA_ULTRA */ - struct sk_buff *conn_skb; /* Store skb here while connecting */ - - struct timer_list watchdog_timer; - - LSAP_STATE lsap_state; /* Connection state */ - notify_t notify; /* Indication/Confirm entry points */ - struct qos_info qos; /* QoS for this connection */ - - struct lap_cb *lap; /* Pointer to LAP connection structure */ -}; - -/* - * Used for caching the last slsap->dlsap->handle mapping - * - * We don't need to keep/match the remote address in the cache because - * we are associated with a specific LAP (which implies it). - * Jean II - */ -typedef struct { - int valid; - - __u8 slsap_sel; - __u8 dlsap_sel; - struct lsap_cb *lsap; -} CACHE_ENTRY; - -/* - * Information about each registered IrLAP layer - */ -struct lap_cb { - irda_queue_t queue; /* Must be first */ - magic_t magic; - - int reason; /* LAP disconnect reason */ - - IRLMP_STATE lap_state; - - struct irlap_cb *irlap; /* Instance of IrLAP layer */ - hashbin_t *lsaps; /* LSAP associated with this link */ - struct lsap_cb *flow_next; /* Next lsap to be polled for Tx */ - - __u8 caddr; /* Connection address */ - __u32 saddr; /* Source device address */ - __u32 daddr; /* Destination device address */ - - struct qos_info *qos; /* LAP QoS for this session */ - struct timer_list idle_timer; - -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - /* The lsap cache was moved from struct irlmp_cb to here because - * it must be associated with the specific LAP. Also, this - * improves performance. - Jean II */ - CACHE_ENTRY cache; /* Caching last slsap->dlsap->handle mapping */ -#endif -}; - -/* - * Main structure for IrLMP - */ -struct irlmp_cb { - magic_t magic; - - __u8 conflict_flag; - - discovery_t discovery_cmd; /* Discovery command to use by IrLAP */ - discovery_t discovery_rsp; /* Discovery response to use by IrLAP */ - - /* Last lsap picked automatically by irlmp_find_free_slsap() */ - int last_lsap_sel; - - struct timer_list discovery_timer; - - hashbin_t *links; /* IrLAP connection table */ - hashbin_t *unconnected_lsaps; - hashbin_t *clients; - hashbin_t *services; - - hashbin_t *cachelog; /* Current discovery log */ - - int running; - - __u16_host_order hints; /* Hint bits */ -}; - -/* Prototype declarations */ -int irlmp_init(void); -void irlmp_cleanup(void); -struct lsap_cb *irlmp_open_lsap(__u8 slsap, notify_t *notify, __u8 pid); -void irlmp_close_lsap( struct lsap_cb *self); - -__u16 irlmp_service_to_hint(int service); -void *irlmp_register_service(__u16 hints); -int irlmp_unregister_service(void *handle); -void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, - DISCOVERY_CALLBACK2 expir_clb, void *priv); -int irlmp_unregister_client(void *handle); -int irlmp_update_client(void *handle, __u16 hint_mask, - DISCOVERY_CALLBACK1 disco_clb, - DISCOVERY_CALLBACK2 expir_clb, void *priv); - -void irlmp_register_link(struct irlap_cb *, __u32 saddr, notify_t *); -void irlmp_unregister_link(__u32 saddr); - -int irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel, - __u32 saddr, __u32 daddr, - struct qos_info *, struct sk_buff *); -void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb); -int irlmp_connect_response(struct lsap_cb *, struct sk_buff *); -void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *); -struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance); - -void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, - struct sk_buff *userdata); -int irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata); - -void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE mode); -void irlmp_discovery_request(int nslots); -discinfo_t *irlmp_get_discoveries(int *pn, __u16 mask, int nslots); -void irlmp_do_expiry(void); -void irlmp_do_discovery(int nslots); -discovery_t *irlmp_get_discovery_response(void); -void irlmp_discovery_expiry(discinfo_t *expiry, int number); - -int irlmp_data_request(struct lsap_cb *, struct sk_buff *); -void irlmp_data_indication(struct lsap_cb *, struct sk_buff *); - -int irlmp_udata_request(struct lsap_cb *, struct sk_buff *); -void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *); - -#ifdef CONFIG_IRDA_ULTRA -int irlmp_connless_data_request(struct lsap_cb *, struct sk_buff *, __u8); -void irlmp_connless_data_indication(struct lsap_cb *, struct sk_buff *); -#endif /* CONFIG_IRDA_ULTRA */ - -void irlmp_status_indication(struct lap_cb *, LINK_STATUS link, LOCK_STATUS lock); -void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow); - -LM_REASON irlmp_convert_lap_reason(LAP_REASON); - -static inline __u32 irlmp_get_saddr(const struct lsap_cb *self) -{ - return (self && self->lap) ? self->lap->saddr : 0; -} - -static inline __u32 irlmp_get_daddr(const struct lsap_cb *self) -{ - return (self && self->lap) ? self->lap->daddr : 0; -} - -const char *irlmp_reason_str(LM_REASON reason); - -extern int sysctl_discovery_timeout; -extern int sysctl_discovery_slots; -extern int sysctl_discovery; -extern int sysctl_lap_keepalive_time; /* in ms, default is LM_IDLE_TIMEOUT */ -extern struct irlmp_cb *irlmp; - -/* Check if LAP queue is full. - * Used by IrTTP for low control, see comments in irlap.h - Jean II */ -static inline int irlmp_lap_tx_queue_full(struct lsap_cb *self) -{ - if (self == NULL) - return 0; - if (self->lap == NULL) - return 0; - if (self->lap->irlap == NULL) - return 0; - - return IRLAP_GET_TX_QUEUE_LEN(self->lap->irlap) >= LAP_HIGH_THRESHOLD; -} - -/* After doing a irlmp_dup(), this get one of the two socket back into - * a state where it's waiting incoming connections. - * Note : this can be used *only* if the socket is not yet connected - * (i.e. NO irlmp_connect_response() done on this socket). - * - Jean II */ -static inline void irlmp_listen(struct lsap_cb *self) -{ - self->dlsap_sel = LSAP_ANY; - self->lap = NULL; - self->lsap_state = LSAP_DISCONNECTED; - /* Started when we received the LM_CONNECT_INDICATION */ - del_timer(&self->watchdog_timer); -} - -#endif diff --git a/drivers/staging/irda/include/net/irda/irlmp_event.h b/drivers/staging/irda/include/net/irda/irlmp_event.h deleted file mode 100644 index a1a082fe384e..000000000000 --- a/drivers/staging/irda/include/net/irda/irlmp_event.h +++ /dev/null @@ -1,98 +0,0 @@ -/********************************************************************* - * - * Filename: irlmp_event.h - * Version: 0.1 - * Description: IrDA-LMP event handling - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Thu Jul 8 12:18:54 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRLMP_EVENT_H -#define IRLMP_EVENT_H - -/* A few forward declarations (to make compiler happy) */ -struct irlmp_cb; -struct lsap_cb; -struct lap_cb; -struct discovery_t; - -/* LAP states */ -typedef enum { - /* IrLAP connection control states */ - LAP_STANDBY, /* No LAP connection */ - LAP_U_CONNECT, /* Starting LAP connection */ - LAP_ACTIVE, /* LAP connection is active */ -} IRLMP_STATE; - -/* LSAP connection control states */ -typedef enum { - LSAP_DISCONNECTED, /* No LSAP connection */ - LSAP_CONNECT, /* Connect indication from peer */ - LSAP_CONNECT_PEND, /* Connect request from service user */ - LSAP_DATA_TRANSFER_READY, /* LSAP connection established */ - LSAP_SETUP, /* Trying to set up LSAP connection */ - LSAP_SETUP_PEND, /* Request to start LAP connection */ -} LSAP_STATE; - -typedef enum { - /* LSAP events */ - LM_CONNECT_REQUEST, - LM_CONNECT_CONFIRM, - LM_CONNECT_RESPONSE, - LM_CONNECT_INDICATION, - - LM_DISCONNECT_INDICATION, - LM_DISCONNECT_REQUEST, - - LM_DATA_REQUEST, - LM_UDATA_REQUEST, - LM_DATA_INDICATION, - LM_UDATA_INDICATION, - - LM_WATCHDOG_TIMEOUT, - - /* IrLAP events */ - LM_LAP_CONNECT_REQUEST, - LM_LAP_CONNECT_INDICATION, - LM_LAP_CONNECT_CONFIRM, - LM_LAP_DISCONNECT_INDICATION, - LM_LAP_DISCONNECT_REQUEST, - LM_LAP_DISCOVERY_REQUEST, - LM_LAP_DISCOVERY_CONFIRM, - LM_LAP_IDLE_TIMEOUT, -} IRLMP_EVENT; - -extern const char *const irlmp_state[]; -extern const char *const irlsap_state[]; - -void irlmp_watchdog_timer_expired(struct timer_list *t); -void irlmp_discovery_timer_expired(struct timer_list *t); -void irlmp_idle_timer_expired(struct timer_list *t); - -void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb); -int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb); - -#endif /* IRLMP_EVENT_H */ - - - - diff --git a/drivers/staging/irda/include/net/irda/irlmp_frame.h b/drivers/staging/irda/include/net/irda/irlmp_frame.h deleted file mode 100644 index 1906eb71422e..000000000000 --- a/drivers/staging/irda/include/net/irda/irlmp_frame.h +++ /dev/null @@ -1,62 +0,0 @@ -/********************************************************************* - * - * Filename: irlmp_frame.h - * Version: 0.9 - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Aug 19 02:09:59 1997 - * Modified at: Fri Dec 10 13:21:53 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRMLP_FRAME_H -#define IRMLP_FRAME_H - -#include <linux/skbuff.h> - -#include <net/irda/discovery.h> - -/* IrLMP frame opcodes */ -#define CONNECT_CMD 0x01 -#define CONNECT_CNF 0x81 -#define DISCONNECT 0x02 -#define ACCESSMODE_CMD 0x03 -#define ACCESSMODE_CNF 0x83 - -#define CONTROL_BIT 0x80 - -void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, - int expedited, struct sk_buff *skb); -void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, - __u8 opcode, struct sk_buff *skb); -void irlmp_link_data_indication(struct lap_cb *, struct sk_buff *, - int unreliable); -#ifdef CONFIG_IRDA_ULTRA -void irlmp_link_unitdata_indication(struct lap_cb *, struct sk_buff *); -#endif /* CONFIG_IRDA_ULTRA */ - -void irlmp_link_connect_indication(struct lap_cb *, __u32 saddr, __u32 daddr, - struct qos_info *qos, struct sk_buff *skb); -void irlmp_link_connect_request(__u32 daddr); -void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, - struct sk_buff *skb); -void irlmp_link_disconnect_indication(struct lap_cb *, struct irlap_cb *, - LAP_REASON reason, struct sk_buff *); -void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log); -void irlmp_link_discovery_indication(struct lap_cb *, discovery_t *discovery); - -#endif diff --git a/drivers/staging/irda/include/net/irda/irmod.h b/drivers/staging/irda/include/net/irda/irmod.h deleted file mode 100644 index 86f0dbb8ee5d..000000000000 --- a/drivers/staging/irda/include/net/irda/irmod.h +++ /dev/null @@ -1,109 +0,0 @@ -/********************************************************************* - * - * Filename: irmod.h - * Version: 0.3 - * Description: IrDA module and utilities functions - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Dec 15 13:58:52 1997 - * Modified at: Fri Jan 28 13:15:24 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charg. - * - ********************************************************************/ - -#ifndef IRMOD_H -#define IRMOD_H - -/* Misc status information */ -typedef enum { - STATUS_OK, - STATUS_ABORTED, - STATUS_NO_ACTIVITY, - STATUS_NOISY, - STATUS_REMOTE, -} LINK_STATUS; - -typedef enum { - LOCK_NO_CHANGE, - LOCK_LOCKED, - LOCK_UNLOCKED, -} LOCK_STATUS; - -typedef enum { FLOW_STOP, FLOW_START } LOCAL_FLOW; - -/* - * IrLMP disconnect reasons. The order is very important, since they - * correspond to disconnect reasons sent in IrLMP disconnect frames, so - * please do not touch :-) - */ -typedef enum { - LM_USER_REQUEST = 1, /* User request */ - LM_LAP_DISCONNECT, /* Unexpected IrLAP disconnect */ - LM_CONNECT_FAILURE, /* Failed to establish IrLAP connection */ - LM_LAP_RESET, /* IrLAP reset */ - LM_INIT_DISCONNECT, /* Link Management initiated disconnect */ - LM_LSAP_NOTCONN, /* Data delivered on unconnected LSAP */ - LM_NON_RESP_CLIENT, /* Non responsive LM-MUX client */ - LM_NO_AVAIL_CLIENT, /* No available LM-MUX client */ - LM_CONN_HALF_OPEN, /* Connection is half open */ - LM_BAD_SOURCE_ADDR, /* Illegal source address (i.e 0x00) */ -} LM_REASON; -#define LM_UNKNOWN 0xff /* Unspecified disconnect reason */ - -/* A few forward declarations (to make compiler happy) */ -struct qos_info; /* in <net/irda/qos.h> */ - -/* - * Notify structure used between transport and link management layers - */ -typedef struct { - int (*data_indication)(void *priv, void *sap, struct sk_buff *skb); - int (*udata_indication)(void *priv, void *sap, struct sk_buff *skb); - void (*connect_confirm)(void *instance, void *sap, - struct qos_info *qos, __u32 max_sdu_size, - __u8 max_header_size, struct sk_buff *skb); - void (*connect_indication)(void *instance, void *sap, - struct qos_info *qos, __u32 max_sdu_size, - __u8 max_header_size, struct sk_buff *skb); - void (*disconnect_indication)(void *instance, void *sap, - LM_REASON reason, struct sk_buff *); - void (*flow_indication)(void *instance, void *sap, LOCAL_FLOW flow); - void (*status_indication)(void *instance, - LINK_STATUS link, LOCK_STATUS lock); - void *instance; /* Layer instance pointer */ - char name[16]; /* Name of layer */ -} notify_t; - -#define NOTIFY_MAX_NAME 16 - -/* Zero the notify structure */ -void irda_notify_init(notify_t *notify); - -/* Locking wrapper - Note the inverted logic on irda_lock(). - * Those function basically return false if the lock is already in the - * position you want to set it. - Jean II */ -#define irda_lock(lock) (! test_and_set_bit(0, (void *) (lock))) -#define irda_unlock(lock) (test_and_clear_bit(0, (void *) (lock))) - -#endif /* IRMOD_H */ - - - - - - - - - diff --git a/drivers/staging/irda/include/net/irda/irqueue.h b/drivers/staging/irda/include/net/irda/irqueue.h deleted file mode 100644 index 37f512bd6733..000000000000 --- a/drivers/staging/irda/include/net/irda/irqueue.h +++ /dev/null @@ -1,96 +0,0 @@ -/********************************************************************* - * - * Filename: irqueue.h - * Version: 0.3 - * Description: General queue implementation - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Jun 9 13:26:50 1998 - * Modified at: Thu Oct 7 13:25:16 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no> - * Copyright (c) 1998, Dag Brattli - * All Rights Reserved. - * - * This code is taken from the Vortex Operating System written by Aage - * Kvalnes and has been ported to Linux and Linux/IR by Dag Brattli - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/types.h> -#include <linux/spinlock.h> - -#ifndef IRDA_QUEUE_H -#define IRDA_QUEUE_H - -#define NAME_SIZE 32 - -/* - * Hash types (some flags can be xored) - * See comments in irqueue.c for which one to use... - */ -#define HB_NOLOCK 0 /* No concurent access prevention */ -#define HB_LOCK 1 /* Prevent concurent write with global lock */ - -/* - * Hash defines - */ -#define HASHBIN_SIZE 8 -#define HASHBIN_MASK 0x7 - -#ifndef IRDA_ALIGN -#define IRDA_ALIGN __attribute__((aligned)) -#endif - -#define Q_NULL { NULL, NULL, "", 0 } - -typedef void (*FREE_FUNC)(void *arg); - -struct irda_queue { - struct irda_queue *q_next; - struct irda_queue *q_prev; - - char q_name[NAME_SIZE]; - long q_hash; /* Must be able to cast a (void *) */ -}; -typedef struct irda_queue irda_queue_t; - -typedef struct hashbin_t { - __u32 magic; - int hb_type; - int hb_size; - spinlock_t hb_spinlock; /* HB_LOCK - Can be used by the user */ - - irda_queue_t* hb_queue[HASHBIN_SIZE] IRDA_ALIGN; - - irda_queue_t* hb_current; -} hashbin_t; - -hashbin_t *hashbin_new(int type); -int hashbin_delete(hashbin_t* hashbin, FREE_FUNC func); -int hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func); -void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, - const char* name); -void* hashbin_remove(hashbin_t* hashbin, long hashv, const char* name); -void* hashbin_remove_first(hashbin_t *hashbin); -void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry); -void* hashbin_find(hashbin_t* hashbin, long hashv, const char* name); -void* hashbin_lock_find(hashbin_t* hashbin, long hashv, const char* name); -void* hashbin_find_next(hashbin_t* hashbin, long hashv, const char* name, - void ** pnext); -irda_queue_t *hashbin_get_first(hashbin_t *hashbin); -irda_queue_t *hashbin_get_next(hashbin_t *hashbin); - -#define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size - -#endif diff --git a/drivers/staging/irda/include/net/irda/irttp.h b/drivers/staging/irda/include/net/irda/irttp.h deleted file mode 100644 index 98682d4bae8f..000000000000 --- a/drivers/staging/irda/include/net/irda/irttp.h +++ /dev/null @@ -1,210 +0,0 @@ -/********************************************************************* - * - * Filename: irttp.h - * Version: 1.0 - * Description: Tiny Transport Protocol (TTP) definitions - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:31 1997 - * Modified at: Sun Dec 12 13:09:07 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRTTP_H -#define IRTTP_H - -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> - -#include <net/irda/irda.h> -#include <net/irda/irlmp.h> /* struct lsap_cb */ -#include <net/irda/qos.h> /* struct qos_info */ -#include <net/irda/irqueue.h> - -#define TTP_MAX_CONNECTIONS LM_MAX_CONNECTIONS -#define TTP_HEADER 1 -#define TTP_MAX_HEADER (TTP_HEADER + LMP_MAX_HEADER) -#define TTP_SAR_HEADER 5 -#define TTP_PARAMETERS 0x80 -#define TTP_MORE 0x80 - -/* Transmission queue sizes */ -/* Worst case scenario, two window of data - Jean II */ -#define TTP_TX_MAX_QUEUE 14 -/* We need to keep at least 5 frames to make sure that we can refill - * appropriately the LAP layer. LAP keeps only two buffers, and we need - * to have 7 to make a full window - Jean II */ -#define TTP_TX_LOW_THRESHOLD 5 -/* Most clients are synchronous with respect to flow control, so we can - * keep a low number of Tx buffers in TTP - Jean II */ -#define TTP_TX_HIGH_THRESHOLD 7 - -/* Receive queue sizes */ -/* Minimum of credit that the peer should hold. - * If the peer has less credits than 9 frames, we will explicitly send - * him some credits (through irttp_give_credit() and a specific frame). - * Note that when we give credits it's likely that it won't be sent in - * this LAP window, but in the next one. So, we make sure that the peer - * has something to send while waiting for credits (one LAP window == 7 - * + 1 frames while he process the credits). - Jean II */ -#define TTP_RX_MIN_CREDIT 8 -/* This is the default maximum number of credits held by the peer, so the - * default maximum number of frames he can send us before needing flow - * control answer from us (this may be negociated differently at TSAP setup). - * We want to minimise the number of times we have to explicitly send some - * credit to the peer, hoping we can piggyback it on the return data. In - * particular, it doesn't make sense for us to send credit more than once - * per LAP window. - * Moreover, giving credits has some latency, so we need strictly more than - * a LAP window, otherwise we may already have credits in our Tx queue. - * But on the other hand, we don't want to keep too many Rx buffer here - * before starting to flow control the other end, so make it exactly one - * LAP window + 1 + MIN_CREDITS. - Jean II */ -#define TTP_RX_DEFAULT_CREDIT 16 -/* Maximum number of credits we can allow the peer to have, and therefore - * maximum Rx queue size. - * Note that we try to deliver packets to the higher layer every time we - * receive something, so in normal mode the Rx queue will never contains - * more than one or two packets. - Jean II */ -#define TTP_RX_MAX_CREDIT 21 - -/* What clients should use when calling ttp_open_tsap() */ -#define DEFAULT_INITIAL_CREDIT TTP_RX_DEFAULT_CREDIT - -/* Some priorities for disconnect requests */ -#define P_NORMAL 0 -#define P_HIGH 1 - -#define TTP_SAR_DISABLE 0 -#define TTP_SAR_UNBOUND 0xffffffff - -/* Parameters */ -#define TTP_MAX_SDU_SIZE 0x01 - -/* - * This structure contains all data associated with one instance of a TTP - * connection. - */ -struct tsap_cb { - irda_queue_t q; /* Must be first */ - magic_t magic; /* Just in case */ - - __u8 stsap_sel; /* Source TSAP */ - __u8 dtsap_sel; /* Destination TSAP */ - - struct lsap_cb *lsap; /* Corresponding LSAP to this TSAP */ - - __u8 connected; /* TSAP connected */ - - __u8 initial_credit; /* Initial credit to give peer */ - - int avail_credit; /* Available credit to return to peer */ - int remote_credit; /* Credit held by peer TTP entity */ - int send_credit; /* Credit held by local TTP entity */ - - struct sk_buff_head tx_queue; /* Frames to be transmitted */ - struct sk_buff_head rx_queue; /* Received frames */ - struct sk_buff_head rx_fragments; - int tx_queue_lock; - int rx_queue_lock; - spinlock_t lock; - - notify_t notify; /* Callbacks to client layer */ - - struct net_device_stats stats; - struct timer_list todo_timer; - - __u32 max_seg_size; /* Max data that fit into an IrLAP frame */ - __u8 max_header_size; - - int rx_sdu_busy; /* RxSdu.busy */ - __u32 rx_sdu_size; /* Current size of a partially received frame */ - __u32 rx_max_sdu_size; /* Max receive user data size */ - - int tx_sdu_busy; /* TxSdu.busy */ - __u32 tx_max_sdu_size; /* Max transmit user data size */ - - int close_pend; /* Close, but disconnect_pend */ - unsigned long disconnect_pend; /* Disconnect, but still data to send */ - struct sk_buff *disconnect_skb; -}; - -struct irttp_cb { - magic_t magic; - hashbin_t *tsaps; -}; - -int irttp_init(void); -void irttp_cleanup(void); - -struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify); -int irttp_close_tsap(struct tsap_cb *self); - -int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb); -int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb); - -int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, - __u32 saddr, __u32 daddr, - struct qos_info *qos, __u32 max_sdu_size, - struct sk_buff *userdata); -int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, - struct sk_buff *userdata); -int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *skb, - int priority); -void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow); -struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance); - -static inline __u32 irttp_get_saddr(struct tsap_cb *self) -{ - return irlmp_get_saddr(self->lsap); -} - -static inline __u32 irttp_get_daddr(struct tsap_cb *self) -{ - return irlmp_get_daddr(self->lsap); -} - -static inline __u32 irttp_get_max_seg_size(struct tsap_cb *self) -{ - return self->max_seg_size; -} - -/* After doing a irttp_dup(), this get one of the two socket back into - * a state where it's waiting incoming connections. - * Note : this can be used *only* if the socket is not yet connected - * (i.e. NO irttp_connect_response() done on this socket). - * - Jean II */ -static inline void irttp_listen(struct tsap_cb *self) -{ - irlmp_listen(self->lsap); - self->dtsap_sel = LSAP_ANY; -} - -/* Return TRUE if the node is in primary mode (i.e. master) - * - Jean II */ -static inline int irttp_is_primary(struct tsap_cb *self) -{ - if ((self == NULL) || - (self->lsap == NULL) || - (self->lsap->lap == NULL) || - (self->lsap->lap->irlap == NULL)) - return -2; - return irlap_is_primary(self->lsap->lap->irlap); -} - -#endif /* IRTTP_H */ diff --git a/drivers/staging/irda/include/net/irda/parameters.h b/drivers/staging/irda/include/net/irda/parameters.h deleted file mode 100644 index 2d9cd0007cba..000000000000 --- a/drivers/staging/irda/include/net/irda/parameters.h +++ /dev/null @@ -1,100 +0,0 @@ -/********************************************************************* - * - * Filename: parameters.h - * Version: 1.0 - * Description: A more general way to handle (pi,pl,pv) parameters - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Jun 7 08:47:28 1999 - * Modified at: Sun Jan 30 14:05:14 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - * Michel Dänzer <daenzer@debian.org>, 10/2001 - * - simplify irda_pv_t to avoid endianness issues - * - ********************************************************************/ - -#ifndef IRDA_PARAMS_H -#define IRDA_PARAMS_H - -/* - * The currently supported types. Beware not to change the sequence since - * it a good reason why the sized integers has a value equal to their size - */ -typedef enum { - PV_INTEGER, /* Integer of any (pl) length */ - PV_INT_8_BITS, /* Integer of 8 bits in length */ - PV_INT_16_BITS, /* Integer of 16 bits in length */ - PV_STRING, /* \0 terminated string */ - PV_INT_32_BITS, /* Integer of 32 bits in length */ - PV_OCT_SEQ, /* Octet sequence */ - PV_NO_VALUE /* Does not contain any value (pl=0) */ -} PV_TYPE; - -/* Bit 7 of type field */ -#define PV_BIG_ENDIAN 0x80 -#define PV_LITTLE_ENDIAN 0x00 -#define PV_MASK 0x7f /* To mask away endian bit */ - -#define PV_PUT 0 -#define PV_GET 1 - -typedef union { - char *c; - __u32 i; - __u32 *ip; -} irda_pv_t; - -typedef struct { - __u8 pi; - __u8 pl; - irda_pv_t pv; -} irda_param_t; - -typedef int (*PI_HANDLER)(void *self, irda_param_t *param, int get); -typedef int (*PV_HANDLER)(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func); - -typedef struct { - const PI_HANDLER func; /* Handler for this parameter identifier */ - PV_TYPE type; /* Data type for this parameter */ -} pi_minor_info_t; - -typedef struct { - const pi_minor_info_t *pi_minor_call_table; - int len; -} pi_major_info_t; - -typedef struct { - const pi_major_info_t *tables; - int len; - __u8 pi_mask; - int pi_major_offset; -} pi_param_info_t; - -int irda_param_pack(__u8 *buf, char *fmt, ...); - -int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, - pi_param_info_t *info); -int irda_param_extract_all(void *self, __u8 *buf, int len, - pi_param_info_t *info); - -#define irda_param_insert_byte(buf,pi,pv) irda_param_pack(buf,"bbb",pi,1,pv) - -#endif /* IRDA_PARAMS_H */ - diff --git a/drivers/staging/irda/include/net/irda/qos.h b/drivers/staging/irda/include/net/irda/qos.h deleted file mode 100644 index a0315b50ac27..000000000000 --- a/drivers/staging/irda/include/net/irda/qos.h +++ /dev/null @@ -1,101 +0,0 @@ -/********************************************************************* - * - * Filename: qos.h - * Version: 1.0 - * Description: Quality of Service definitions - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri Sep 19 23:21:09 1997 - * Modified at: Thu Dec 2 13:51:54 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#ifndef IRDA_QOS_H -#define IRDA_QOS_H - -#include <linux/skbuff.h> - -#include <net/irda/parameters.h> - -#define PI_BAUD_RATE 0x01 -#define PI_MAX_TURN_TIME 0x82 -#define PI_DATA_SIZE 0x83 -#define PI_WINDOW_SIZE 0x84 -#define PI_ADD_BOFS 0x85 -#define PI_MIN_TURN_TIME 0x86 -#define PI_LINK_DISC 0x08 - -#define IR_115200_MAX 0x3f - -/* Baud rates (first byte) */ -#define IR_2400 0x01 -#define IR_9600 0x02 -#define IR_19200 0x04 -#define IR_38400 0x08 -#define IR_57600 0x10 -#define IR_115200 0x20 -#define IR_576000 0x40 -#define IR_1152000 0x80 - -/* Baud rates (second byte) */ -#define IR_4000000 0x01 -#define IR_16000000 0x02 - -/* Quality of Service information */ -struct qos_value { - __u32 value; - __u16 bits; /* LSB is first byte, MSB is second byte */ -}; - -struct qos_info { - magic_t magic; - - struct qos_value baud_rate; /* IR_11520O | ... */ - struct qos_value max_turn_time; - struct qos_value data_size; - struct qos_value window_size; - struct qos_value additional_bofs; - struct qos_value min_turn_time; - struct qos_value link_disc_time; - - struct qos_value power; -}; - -extern int sysctl_max_baud_rate; -extern int sysctl_max_inactive_time; - -void irda_init_max_qos_capabilies(struct qos_info *qos); -void irda_qos_compute_intersection(struct qos_info *, struct qos_info *); - -__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time); - -void irda_qos_bits_to_value(struct qos_info *qos); - -/* So simple, how could we not inline those two ? - * Note : one byte is 10 bits if you include start and stop bits - * Jean II */ -#define irlap_min_turn_time_in_bytes(speed, min_turn_time) ( \ - speed * min_turn_time / 10000000 \ -) -#define irlap_xbofs_in_usec(speed, xbofs) ( \ - xbofs * 10000000 / speed \ -) - -#endif - diff --git a/drivers/staging/irda/include/net/irda/timer.h b/drivers/staging/irda/include/net/irda/timer.h deleted file mode 100644 index 6dab15f5dae1..000000000000 --- a/drivers/staging/irda/include/net/irda/timer.h +++ /dev/null @@ -1,102 +0,0 @@ -/********************************************************************* - * - * Filename: timer.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Aug 16 00:59:29 1997 - * Modified at: Thu Oct 7 12:25:24 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef TIMER_H -#define TIMER_H - -#include <linux/timer.h> -#include <linux/jiffies.h> - -#include <asm/param.h> /* for HZ */ - -#include <net/irda/irda.h> - -/* A few forward declarations (to make compiler happy) */ -struct irlmp_cb; -struct irlap_cb; -struct lsap_cb; -struct lap_cb; - -/* - * Timeout definitions, some defined in IrLAP 6.13.5 - p. 92 - */ -#define POLL_TIMEOUT (450*HZ/1000) /* Must never exceed 500 ms */ -#define FINAL_TIMEOUT (500*HZ/1000) /* Must never exceed 500 ms */ - -/* - * Normally twice of p-timer. Note 3, IrLAP 6.3.11.2 - p. 60 suggests - * at least twice duration of the P-timer. - */ -#define WD_TIMEOUT (POLL_TIMEOUT*2) - -#define MEDIABUSY_TIMEOUT (500*HZ/1000) /* 500 msec */ -#define SMALLBUSY_TIMEOUT (100*HZ/1000) /* 100 msec - IrLAP 6.13.4 */ - -/* - * Slot timer must never exceed 85 ms, and must always be at least 25 ms, - * suggested to 75-85 msec by IrDA lite. This doesn't work with a lot of - * devices, and other stackes uses a lot more, so it's best we do it as well - * (Note : this is the default value and sysctl overrides it - Jean II) - */ -#define SLOT_TIMEOUT (90*HZ/1000) - -/* - * The latest discovery frame (XID) is longer due to the extra discovery - * information (hints, device name...). This is its extra length. - * We use that when setting the query timeout. Jean II - */ -#define XIDEXTRA_TIMEOUT (34*HZ/1000) /* 34 msec */ - -#define WATCHDOG_TIMEOUT (20*HZ) /* 20 sec */ - -static inline void irda_start_timer(struct timer_list *ptimer, int timeout, - void (*callback)(struct timer_list *)) -{ - ptimer->function = callback; - - /* Set new value for timer (update or add timer). - * We use mod_timer() because it's more efficient and also - * safer with respect to race conditions - Jean II */ - mod_timer(ptimer, jiffies + timeout); -} - - -void irlap_start_slot_timer(struct irlap_cb *self, int timeout); -void irlap_start_query_timer(struct irlap_cb *self, int S, int s); -void irlap_start_final_timer(struct irlap_cb *self, int timeout); -void irlap_start_wd_timer(struct irlap_cb *self, int timeout); -void irlap_start_backoff_timer(struct irlap_cb *self, int timeout); - -void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout); -void irlap_stop_mbusy_timer(struct irlap_cb *); - -void irlmp_start_watchdog_timer(struct lsap_cb *, int timeout); -void irlmp_start_discovery_timer(struct irlmp_cb *, int timeout); -void irlmp_start_idle_timer(struct lap_cb *, int timeout); -void irlmp_stop_idle_timer(struct lap_cb *self); - -#endif - diff --git a/drivers/staging/irda/include/net/irda/wrapper.h b/drivers/staging/irda/include/net/irda/wrapper.h deleted file mode 100644 index eef53ebe3d76..000000000000 --- a/drivers/staging/irda/include/net/irda/wrapper.h +++ /dev/null @@ -1,58 +0,0 @@ -/********************************************************************* - * - * Filename: wrapper.h - * Version: 1.2 - * Description: IrDA SIR async wrapper layer - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Tue Jan 11 12:37:29 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef WRAPPER_H -#define WRAPPER_H - -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> - -#include <net/irda/irda_device.h> /* iobuff_t */ - -#define BOF 0xc0 /* Beginning of frame */ -#define XBOF 0xff -#define EOF 0xc1 /* End of frame */ -#define CE 0x7d /* Control escape */ - -#define STA BOF /* Start flag */ -#define STO EOF /* End flag */ - -#define IRDA_TRANS 0x20 /* Asynchronous transparency modifier */ - -/* States for receiving a frame in async mode */ -enum { - OUTSIDE_FRAME, - BEGIN_FRAME, - LINK_ESCAPE, - INSIDE_FRAME -}; - -/* Proto definitions */ -int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize); -void async_unwrap_char(struct net_device *dev, struct net_device_stats *stats, - iobuff_t *buf, __u8 byte); - -#endif diff --git a/drivers/staging/irda/net/Kconfig b/drivers/staging/irda/net/Kconfig deleted file mode 100644 index 6abeae6c666a..000000000000 --- a/drivers/staging/irda/net/Kconfig +++ /dev/null @@ -1,96 +0,0 @@ -# -# IrDA protocol configuration -# - -menuconfig IRDA - depends on NET && !S390 - tristate "IrDA (infrared) subsystem support" - select CRC_CCITT - ---help--- - Say Y here if you want to build support for the IrDA (TM) protocols. - The Infrared Data Associations (tm) specifies standards for wireless - infrared communication and is supported by most laptops and PDA's. - - To use Linux support for the IrDA (tm) protocols, you will also need - some user-space utilities like irattach. For more information, see - the file <file:Documentation/networking/irda.txt>. You also want to - read the IR-HOWTO, available at - <http://www.tldp.org/docs.html#howto>. - - If you want to exchange bits of data (vCal, vCard) with a PDA, you - will need to install some OBEX application, such as OpenObex : - <http://sourceforge.net/projects/openobex/> - - To compile this support as a module, choose M here: the module will - be called irda. - -comment "IrDA protocols" - depends on IRDA - -source "drivers/staging/irda/net/irlan/Kconfig" - -source "drivers/staging/irda/net/irnet/Kconfig" - -source "drivers/staging/irda/net/ircomm/Kconfig" - -config IRDA_ULTRA - bool "Ultra (connectionless) protocol" - depends on IRDA - help - Say Y here to support the connectionless Ultra IRDA protocol. - Ultra allows to exchange data over IrDA with really simple devices - (watch, beacon) without the overhead of the IrDA protocol (no handshaking, - no management frames, simple fixed header). - Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1); - -comment "IrDA options" - depends on IRDA - -config IRDA_CACHE_LAST_LSAP - bool "Cache last LSAP" - depends on IRDA - help - Say Y here if you want IrLMP to cache the last LSAP used. This - makes sense since most frames will be sent/received on the same - connection. Enabling this option will save a hash-lookup per frame. - - If unsure, say Y. - -config IRDA_FAST_RR - bool "Fast RRs (low latency)" - depends on IRDA - ---help--- - Say Y here is you want IrLAP to send fast RR (Receive Ready) frames - when acting as a primary station. - Disabling this option will make latency over IrDA very bad. Enabling - this option will make the IrDA stack send more packet than strictly - necessary, thus reduce your battery life (but not that much). - - Fast RR will make IrLAP send out a RR frame immediately when - receiving a frame if its own transmit queue is currently empty. This - will give a lot of speed improvement when receiving much data since - the secondary station will not have to wait the max. turn around - time (usually 500ms) before it is allowed to transmit the next time. - If the transmit queue of the secondary is also empty, the primary will - start backing-off before sending another RR frame, waiting longer - each time until the back-off reaches the max. turn around time. - This back-off increase in controlled via - /proc/sys/net/irda/fast_poll_increase - - If unsure, say Y. - -config IRDA_DEBUG - bool "Debug information" - depends on IRDA - help - Say Y here if you want the IrDA subsystem to write debug information - to your syslog. You can change the debug level in - /proc/sys/net/irda/debug . - When this option is enabled, the IrDA also perform many extra internal - verifications which will usually prevent the kernel to crash in case of - bugs. - - If unsure, say Y (since it makes it easier to find the bugs). - -source "drivers/staging/irda/drivers/Kconfig" - diff --git a/drivers/staging/irda/net/Makefile b/drivers/staging/irda/net/Makefile deleted file mode 100644 index bd1a635b88cf..000000000000 --- a/drivers/staging/irda/net/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# -# Makefile for the Linux IrDA protocol layer. -# - -subdir-ccflags-y += -I$(srctree)/drivers/staging/irda/include - -obj-$(CONFIG_IRDA) += irda.o -obj-$(CONFIG_IRLAN) += irlan/ -obj-$(CONFIG_IRNET) += irnet/ -obj-$(CONFIG_IRCOMM) += ircomm/ - -irda-y := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \ - irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \ - irttp.o irda_device.o irias_object.o wrapper.o af_irda.o \ - discovery.o parameters.o irnetlink.o irmod.o -irda-$(CONFIG_PROC_FS) += irproc.o -irda-$(CONFIG_SYSCTL) += irsysctl.o diff --git a/drivers/staging/irda/net/af_irda.c b/drivers/staging/irda/net/af_irda.c deleted file mode 100644 index c13553a9ee11..000000000000 --- a/drivers/staging/irda/net/af_irda.c +++ /dev/null @@ -1,2692 +0,0 @@ -/********************************************************************* - * - * Filename: af_irda.c - * Version: 0.9 - * Description: IrDA sockets implementation - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun May 31 10:12:43 1998 - * Modified at: Sat Dec 25 21:10:23 1999 - * Modified by: Dag Brattli <dag@brattli.net> - * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. - * - * Copyright (c) 1999 Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1999-2003 Jean Tourrilhes <jt@hpl.hp.com> - * All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - * Linux-IrDA now supports four different types of IrDA sockets: - * - * o SOCK_STREAM: TinyTP connections with SAR disabled. The - * max SDU size is 0 for conn. of this type - * o SOCK_SEQPACKET: TinyTP connections with SAR enabled. TTP may - * fragment the messages, but will preserve - * the message boundaries - * o SOCK_DGRAM: IRDAPROTO_UNITDATA: TinyTP connections with Unitdata - * (unreliable) transfers - * IRDAPROTO_ULTRA: Connectionless and unreliable data - * - ********************************************************************/ - -#include <linux/capability.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/socket.h> -#include <linux/sockios.h> -#include <linux/slab.h> -#include <linux/sched/signal.h> -#include <linux/init.h> -#include <linux/net.h> -#include <linux/irda.h> -#include <linux/poll.h> - -#include <asm/ioctls.h> /* TIOCOUTQ, TIOCINQ */ -#include <linux/uaccess.h> - -#include <net/sock.h> -#include <net/tcp_states.h> - -#include <net/irda/af_irda.h> - -static int irda_create(struct net *net, struct socket *sock, int protocol, int kern); - -static const struct proto_ops irda_stream_ops; -static const struct proto_ops irda_seqpacket_ops; -static const struct proto_ops irda_dgram_ops; - -#ifdef CONFIG_IRDA_ULTRA -static const struct proto_ops irda_ultra_ops; -#define ULTRA_MAX_DATA 382 -#endif /* CONFIG_IRDA_ULTRA */ - -#define IRDA_MAX_HEADER (TTP_MAX_HEADER) - -/* - * Function irda_data_indication (instance, sap, skb) - * - * Received some data from TinyTP. Just queue it on the receive queue - * - */ -static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb) -{ - struct irda_sock *self; - struct sock *sk; - int err; - - self = instance; - sk = instance; - - err = sock_queue_rcv_skb(sk, skb); - if (err) { - pr_debug("%s(), error: no more mem!\n", __func__); - self->rx_flow = FLOW_STOP; - - /* When we return error, TTP will need to requeue the skb */ - return err; - } - - return 0; -} - -/* - * Function irda_disconnect_indication (instance, sap, reason, skb) - * - * Connection has been closed. Check reason to find out why - * - */ -static void irda_disconnect_indication(void *instance, void *sap, - LM_REASON reason, struct sk_buff *skb) -{ - struct irda_sock *self; - struct sock *sk; - - self = instance; - - pr_debug("%s(%p)\n", __func__, self); - - /* Don't care about it, but let's not leak it */ - if(skb) - dev_kfree_skb(skb); - - sk = instance; - if (sk == NULL) { - pr_debug("%s(%p) : BUG : sk is NULL\n", - __func__, self); - return; - } - - /* Prevent race conditions with irda_release() and irda_shutdown() */ - bh_lock_sock(sk); - if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) { - sk->sk_state = TCP_CLOSE; - sk->sk_shutdown |= SEND_SHUTDOWN; - - sk->sk_state_change(sk); - - /* Close our TSAP. - * If we leave it open, IrLMP put it back into the list of - * unconnected LSAPs. The problem is that any incoming request - * can then be matched to this socket (and it will be, because - * it is at the head of the list). This would prevent any - * listening socket waiting on the same TSAP to get those - * requests. Some apps forget to close sockets, or hang to it - * a bit too long, so we may stay in this dead state long - * enough to be noticed... - * Note : all socket function do check sk->sk_state, so we are - * safe... - * Jean II - */ - if (self->tsap) { - irttp_close_tsap(self->tsap); - self->tsap = NULL; - } - } - bh_unlock_sock(sk); - - /* Note : once we are there, there is not much you want to do - * with the socket anymore, apart from closing it. - * For example, bind() and connect() won't reset sk->sk_err, - * sk->sk_shutdown and sk->sk_flags to valid values... - * Jean II - */ -} - -/* - * Function irda_connect_confirm (instance, sap, qos, max_sdu_size, skb) - * - * Connections has been confirmed by the remote device - * - */ -static void irda_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, __u8 max_header_size, - struct sk_buff *skb) -{ - struct irda_sock *self; - struct sock *sk; - - self = instance; - - pr_debug("%s(%p)\n", __func__, self); - - sk = instance; - if (sk == NULL) { - dev_kfree_skb(skb); - return; - } - - dev_kfree_skb(skb); - // Should be ??? skb_queue_tail(&sk->sk_receive_queue, skb); - - /* How much header space do we need to reserve */ - self->max_header_size = max_header_size; - - /* IrTTP max SDU size in transmit direction */ - self->max_sdu_size_tx = max_sdu_size; - - /* Find out what the largest chunk of data that we can transmit is */ - switch (sk->sk_type) { - case SOCK_STREAM: - if (max_sdu_size != 0) { - net_err_ratelimited("%s: max_sdu_size must be 0\n", - __func__); - return; - } - self->max_data_size = irttp_get_max_seg_size(self->tsap); - break; - case SOCK_SEQPACKET: - if (max_sdu_size == 0) { - net_err_ratelimited("%s: max_sdu_size cannot be 0\n", - __func__); - return; - } - self->max_data_size = max_sdu_size; - break; - default: - self->max_data_size = irttp_get_max_seg_size(self->tsap); - } - - pr_debug("%s(), max_data_size=%d\n", __func__, - self->max_data_size); - - memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); - - /* We are now connected! */ - sk->sk_state = TCP_ESTABLISHED; - sk->sk_state_change(sk); -} - -/* - * Function irda_connect_indication(instance, sap, qos, max_sdu_size, userdata) - * - * Incoming connection - * - */ -static void irda_connect_indication(void *instance, void *sap, - struct qos_info *qos, __u32 max_sdu_size, - __u8 max_header_size, struct sk_buff *skb) -{ - struct irda_sock *self; - struct sock *sk; - - self = instance; - - pr_debug("%s(%p)\n", __func__, self); - - sk = instance; - if (sk == NULL) { - dev_kfree_skb(skb); - return; - } - - /* How much header space do we need to reserve */ - self->max_header_size = max_header_size; - - /* IrTTP max SDU size in transmit direction */ - self->max_sdu_size_tx = max_sdu_size; - - /* Find out what the largest chunk of data that we can transmit is */ - switch (sk->sk_type) { - case SOCK_STREAM: - if (max_sdu_size != 0) { - net_err_ratelimited("%s: max_sdu_size must be 0\n", - __func__); - kfree_skb(skb); - return; - } - self->max_data_size = irttp_get_max_seg_size(self->tsap); - break; - case SOCK_SEQPACKET: - if (max_sdu_size == 0) { - net_err_ratelimited("%s: max_sdu_size cannot be 0\n", - __func__); - kfree_skb(skb); - return; - } - self->max_data_size = max_sdu_size; - break; - default: - self->max_data_size = irttp_get_max_seg_size(self->tsap); - } - - pr_debug("%s(), max_data_size=%d\n", __func__, - self->max_data_size); - - memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); - - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_state_change(sk); -} - -/* - * Function irda_connect_response (handle) - * - * Accept incoming connection - * - */ -static void irda_connect_response(struct irda_sock *self) -{ - struct sk_buff *skb; - - skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_KERNEL); - if (skb == NULL) { - pr_debug("%s() Unable to allocate sk_buff!\n", - __func__); - return; - } - - /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve(skb, IRDA_MAX_HEADER); - - irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb); -} - -/* - * Function irda_flow_indication (instance, sap, flow) - * - * Used by TinyTP to tell us if it can accept more data or not - * - */ -static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) -{ - struct irda_sock *self; - struct sock *sk; - - self = instance; - sk = instance; - BUG_ON(sk == NULL); - - switch (flow) { - case FLOW_STOP: - pr_debug("%s(), IrTTP wants us to slow down\n", - __func__); - self->tx_flow = flow; - break; - case FLOW_START: - self->tx_flow = flow; - pr_debug("%s(), IrTTP wants us to start again\n", - __func__); - wake_up_interruptible(sk_sleep(sk)); - break; - default: - pr_debug("%s(), Unknown flow command!\n", __func__); - /* Unknown flow command, better stop */ - self->tx_flow = flow; - break; - } -} - -/* - * Function irda_getvalue_confirm (obj_id, value, priv) - * - * Got answer from remote LM-IAS, just pass object to requester... - * - * Note : duplicate from above, but we need our own version that - * doesn't touch the dtsap_sel and save the full value structure... - */ -static void irda_getvalue_confirm(int result, __u16 obj_id, - struct ias_value *value, void *priv) -{ - struct irda_sock *self; - - self = priv; - if (!self) { - net_warn_ratelimited("%s: lost myself!\n", __func__); - return; - } - - pr_debug("%s(%p)\n", __func__, self); - - /* We probably don't need to make any more queries */ - iriap_close(self->iriap); - self->iriap = NULL; - - /* Check if request succeeded */ - if (result != IAS_SUCCESS) { - pr_debug("%s(), IAS query failed! (%d)\n", __func__, - result); - - self->errno = result; /* We really need it later */ - - /* Wake up any processes waiting for result */ - wake_up_interruptible(&self->query_wait); - - return; - } - - /* Pass the object to the caller (so the caller must delete it) */ - self->ias_result = value; - self->errno = 0; - - /* Wake up any processes waiting for result */ - wake_up_interruptible(&self->query_wait); -} - -/* - * Function irda_selective_discovery_indication (discovery) - * - * Got a selective discovery indication from IrLMP. - * - * IrLMP is telling us that this node is new and matching our hint bit - * filter. Wake up any process waiting for answer... - */ -static void irda_selective_discovery_indication(discinfo_t *discovery, - DISCOVERY_MODE mode, - void *priv) -{ - struct irda_sock *self; - - self = priv; - if (!self) { - net_warn_ratelimited("%s: lost myself!\n", __func__); - return; - } - - /* Pass parameter to the caller */ - self->cachedaddr = discovery->daddr; - - /* Wake up process if its waiting for device to be discovered */ - wake_up_interruptible(&self->query_wait); -} - -/* - * Function irda_discovery_timeout (priv) - * - * Timeout in the selective discovery process - * - * We were waiting for a node to be discovered, but nothing has come up - * so far. Wake up the user and tell him that we failed... - */ -static void irda_discovery_timeout(struct timer_list *t) -{ - struct irda_sock *self; - - self = from_timer(self, t, watchdog); - BUG_ON(self == NULL); - - /* Nothing for the caller */ - self->cachelog = NULL; - self->cachedaddr = 0; - self->errno = -ETIME; - - /* Wake up process if its still waiting... */ - wake_up_interruptible(&self->query_wait); -} - -/* - * Function irda_open_tsap (self) - * - * Open local Transport Service Access Point (TSAP) - * - */ -static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name) -{ - notify_t notify; - - if (self->tsap) { - pr_debug("%s: busy!\n", __func__); - return -EBUSY; - } - - /* Initialize callbacks to be used by the IrDA stack */ - irda_notify_init(¬ify); - notify.connect_confirm = irda_connect_confirm; - notify.connect_indication = irda_connect_indication; - notify.disconnect_indication = irda_disconnect_indication; - notify.data_indication = irda_data_indication; - notify.udata_indication = irda_data_indication; - notify.flow_indication = irda_flow_indication; - notify.instance = self; - strncpy(notify.name, name, NOTIFY_MAX_NAME); - - self->tsap = irttp_open_tsap(tsap_sel, DEFAULT_INITIAL_CREDIT, - ¬ify); - if (self->tsap == NULL) { - pr_debug("%s(), Unable to allocate TSAP!\n", - __func__); - return -ENOMEM; - } - /* Remember which TSAP selector we actually got */ - self->stsap_sel = self->tsap->stsap_sel; - - return 0; -} - -/* - * Function irda_open_lsap (self) - * - * Open local Link Service Access Point (LSAP). Used for opening Ultra - * sockets - */ -#ifdef CONFIG_IRDA_ULTRA -static int irda_open_lsap(struct irda_sock *self, int pid) -{ - notify_t notify; - - if (self->lsap) { - net_warn_ratelimited("%s(), busy!\n", __func__); - return -EBUSY; - } - - /* Initialize callbacks to be used by the IrDA stack */ - irda_notify_init(¬ify); - notify.udata_indication = irda_data_indication; - notify.instance = self; - strncpy(notify.name, "Ultra", NOTIFY_MAX_NAME); - - self->lsap = irlmp_open_lsap(LSAP_CONNLESS, ¬ify, pid); - if (self->lsap == NULL) { - pr_debug("%s(), Unable to allocate LSAP!\n", __func__); - return -ENOMEM; - } - - return 0; -} -#endif /* CONFIG_IRDA_ULTRA */ - -/* - * Function irda_find_lsap_sel (self, name) - * - * Try to lookup LSAP selector in remote LM-IAS - * - * Basically, we start a IAP query, and then go to sleep. When the query - * return, irda_getvalue_confirm will wake us up, and we can examine the - * result of the query... - * Note that in some case, the query fail even before we go to sleep, - * creating some races... - */ -static int irda_find_lsap_sel(struct irda_sock *self, char *name) -{ - pr_debug("%s(%p, %s)\n", __func__, self, name); - - if (self->iriap) { - net_warn_ratelimited("%s(): busy with a previous query\n", - __func__); - return -EBUSY; - } - - self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - irda_getvalue_confirm); - if(self->iriap == NULL) - return -ENOMEM; - - /* Treat unexpected wakeup as disconnect */ - self->errno = -EHOSTUNREACH; - - /* Query remote LM-IAS */ - iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr, - name, "IrDA:TinyTP:LsapSel"); - - /* Wait for answer, if not yet finished (or failed) */ - if (wait_event_interruptible(self->query_wait, (self->iriap==NULL))) - /* Treat signals as disconnect */ - return -EHOSTUNREACH; - - /* Check what happened */ - if (self->errno) - { - /* Requested object/attribute doesn't exist */ - if((self->errno == IAS_CLASS_UNKNOWN) || - (self->errno == IAS_ATTRIB_UNKNOWN)) - return -EADDRNOTAVAIL; - else - return -EHOSTUNREACH; - } - - /* Get the remote TSAP selector */ - switch (self->ias_result->type) { - case IAS_INTEGER: - pr_debug("%s() int=%d\n", - __func__, self->ias_result->t.integer); - - if (self->ias_result->t.integer != -1) - self->dtsap_sel = self->ias_result->t.integer; - else - self->dtsap_sel = 0; - break; - default: - self->dtsap_sel = 0; - pr_debug("%s(), bad type!\n", __func__); - break; - } - if (self->ias_result) - irias_delete_value(self->ias_result); - - if (self->dtsap_sel) - return 0; - - return -EADDRNOTAVAIL; -} - -/* - * Function irda_discover_daddr_and_lsap_sel (self, name) - * - * This try to find a device with the requested service. - * - * It basically look into the discovery log. For each address in the list, - * it queries the LM-IAS of the device to find if this device offer - * the requested service. - * If there is more than one node supporting the service, we complain - * to the user (it should move devices around). - * The, we set both the destination address and the lsap selector to point - * on the service on the unique device we have found. - * - * Note : this function fails if there is more than one device in range, - * because IrLMP doesn't disconnect the LAP when the last LSAP is closed. - * Moreover, we would need to wait the LAP disconnection... - */ -static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) -{ - discinfo_t *discoveries; /* Copy of the discovery log */ - int number; /* Number of nodes in the log */ - int i; - int err = -ENETUNREACH; - __u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */ - __u8 dtsap_sel = 0x0; /* TSAP associated with it */ - - pr_debug("%s(), name=%s\n", __func__, name); - - /* Ask lmp for the current discovery log - * Note : we have to use irlmp_get_discoveries(), as opposed - * to play with the cachelog directly, because while we are - * making our ias query, le log might change... */ - discoveries = irlmp_get_discoveries(&number, self->mask.word, - self->nslots); - /* Check if the we got some results */ - if (discoveries == NULL) - return -ENETUNREACH; /* No nodes discovered */ - - /* - * Now, check all discovered devices (if any), and connect - * client only about the services that the client is - * interested in... - */ - for(i = 0; i < number; i++) { - /* Try the address in the log */ - self->daddr = discoveries[i].daddr; - self->saddr = 0x0; - pr_debug("%s(), trying daddr = %08x\n", - __func__, self->daddr); - - /* Query remote LM-IAS for this service */ - err = irda_find_lsap_sel(self, name); - switch (err) { - case 0: - /* We found the requested service */ - if(daddr != DEV_ADDR_ANY) { - pr_debug("%s(), discovered service ''%s'' in two different devices !!!\n", - __func__, name); - self->daddr = DEV_ADDR_ANY; - kfree(discoveries); - return -ENOTUNIQ; - } - /* First time we found that one, save it ! */ - daddr = self->daddr; - dtsap_sel = self->dtsap_sel; - break; - case -EADDRNOTAVAIL: - /* Requested service simply doesn't exist on this node */ - break; - default: - /* Something bad did happen :-( */ - pr_debug("%s(), unexpected IAS query failure\n", - __func__); - self->daddr = DEV_ADDR_ANY; - kfree(discoveries); - return -EHOSTUNREACH; - } - } - /* Cleanup our copy of the discovery log */ - kfree(discoveries); - - /* Check out what we found */ - if(daddr == DEV_ADDR_ANY) { - pr_debug("%s(), cannot discover service ''%s'' in any device !!!\n", - __func__, name); - self->daddr = DEV_ADDR_ANY; - return -EADDRNOTAVAIL; - } - - /* Revert back to discovered device & service */ - self->daddr = daddr; - self->saddr = 0x0; - self->dtsap_sel = dtsap_sel; - - pr_debug("%s(), discovered requested service ''%s'' at address %08x\n", - __func__, name, self->daddr); - - return 0; -} - -/* - * Function irda_getname (sock, uaddr, uaddr_len, peer) - * - * Return the our own, or peers socket address (sockaddr_irda) - * - */ -static int irda_getname(struct socket *sock, struct sockaddr *uaddr, - int peer) -{ - struct sockaddr_irda saddr; - struct sock *sk = sock->sk; - struct irda_sock *self = irda_sk(sk); - - memset(&saddr, 0, sizeof(saddr)); - if (peer) { - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; - - saddr.sir_family = AF_IRDA; - saddr.sir_lsap_sel = self->dtsap_sel; - saddr.sir_addr = self->daddr; - } else { - saddr.sir_family = AF_IRDA; - saddr.sir_lsap_sel = self->stsap_sel; - saddr.sir_addr = self->saddr; - } - - pr_debug("%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel); - pr_debug("%s(), addr = %08x\n", __func__, saddr.sir_addr); - - memcpy(uaddr, &saddr, sizeof (struct sockaddr_irda)); - - return sizeof (struct sockaddr_irda); -} - -/* - * Function irda_listen (sock, backlog) - * - * Just move to the listen state - * - */ -static int irda_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - int err = -EOPNOTSUPP; - - lock_sock(sk); - - if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && - (sk->sk_type != SOCK_DGRAM)) - goto out; - - if (sk->sk_state != TCP_LISTEN) { - sk->sk_max_ack_backlog = backlog; - sk->sk_state = TCP_LISTEN; - - err = 0; - } -out: - release_sock(sk); - - return err; -} - -/* - * Function irda_bind (sock, uaddr, addr_len) - * - * Used by servers to register their well known TSAP - * - */ -static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) -{ - struct sock *sk = sock->sk; - struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr; - struct irda_sock *self = irda_sk(sk); - int err; - - pr_debug("%s(%p)\n", __func__, self); - - if (addr_len != sizeof(struct sockaddr_irda)) - return -EINVAL; - - lock_sock(sk); -#ifdef CONFIG_IRDA_ULTRA - /* Special care for Ultra sockets */ - if ((sk->sk_type == SOCK_DGRAM) && - (sk->sk_protocol == IRDAPROTO_ULTRA)) { - self->pid = addr->sir_lsap_sel; - err = -EOPNOTSUPP; - if (self->pid & 0x80) { - pr_debug("%s(), extension in PID not supp!\n", - __func__); - goto out; - } - err = irda_open_lsap(self, self->pid); - if (err < 0) - goto out; - - /* Pretend we are connected */ - sock->state = SS_CONNECTED; - sk->sk_state = TCP_ESTABLISHED; - err = 0; - - goto out; - } -#endif /* CONFIG_IRDA_ULTRA */ - - self->ias_obj = irias_new_object(addr->sir_name, jiffies); - err = -ENOMEM; - if (self->ias_obj == NULL) - goto out; - - err = irda_open_tsap(self, addr->sir_lsap_sel, addr->sir_name); - if (err < 0) { - irias_delete_object(self->ias_obj); - self->ias_obj = NULL; - goto out; - } - - /* Register with LM-IAS */ - irias_add_integer_attrib(self->ias_obj, "IrDA:TinyTP:LsapSel", - self->stsap_sel, IAS_KERNEL_ATTR); - irias_insert_object(self->ias_obj); - - err = 0; -out: - release_sock(sk); - return err; -} - -/* - * Function irda_accept (sock, newsock, flags) - * - * Wait for incoming connection - * - */ -static int irda_accept(struct socket *sock, struct socket *newsock, int flags, - bool kern) -{ - struct sock *sk = sock->sk; - struct irda_sock *new, *self = irda_sk(sk); - struct sock *newsk; - struct sk_buff *skb = NULL; - int err; - - err = irda_create(sock_net(sk), newsock, sk->sk_protocol, kern); - if (err) - return err; - - err = -EINVAL; - - lock_sock(sk); - if (sock->state != SS_UNCONNECTED) - goto out; - - err = -EOPNOTSUPP; - if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && - (sk->sk_type != SOCK_DGRAM)) - goto out; - - err = -EINVAL; - if (sk->sk_state != TCP_LISTEN) - goto out; - - /* - * The read queue this time is holding sockets ready to use - * hooked into the SABM we saved - */ - - /* - * We can perform the accept only if there is incoming data - * on the listening socket. - * So, we will block the caller until we receive any data. - * If the caller was waiting on select() or poll() before - * calling us, the data is waiting for us ;-) - * Jean II - */ - while (1) { - skb = skb_dequeue(&sk->sk_receive_queue); - if (skb) - break; - - /* Non blocking operation */ - err = -EWOULDBLOCK; - if (flags & O_NONBLOCK) - goto out; - - err = wait_event_interruptible(*(sk_sleep(sk)), - skb_peek(&sk->sk_receive_queue)); - if (err) - goto out; - } - - newsk = newsock->sk; - err = -EIO; - if (newsk == NULL) - goto out; - - newsk->sk_state = TCP_ESTABLISHED; - - new = irda_sk(newsk); - - /* Now attach up the new socket */ - new->tsap = irttp_dup(self->tsap, new); - err = -EPERM; /* value does not seem to make sense. -arnd */ - if (!new->tsap) { - pr_debug("%s(), dup failed!\n", __func__); - goto out; - } - - new->stsap_sel = new->tsap->stsap_sel; - new->dtsap_sel = new->tsap->dtsap_sel; - new->saddr = irttp_get_saddr(new->tsap); - new->daddr = irttp_get_daddr(new->tsap); - - new->max_sdu_size_tx = self->max_sdu_size_tx; - new->max_sdu_size_rx = self->max_sdu_size_rx; - new->max_data_size = self->max_data_size; - new->max_header_size = self->max_header_size; - - memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info)); - - /* Clean up the original one to keep it in listen state */ - irttp_listen(self->tsap); - - sk->sk_ack_backlog--; - - newsock->state = SS_CONNECTED; - - irda_connect_response(new); - err = 0; -out: - kfree_skb(skb); - release_sock(sk); - return err; -} - -/* - * Function irda_connect (sock, uaddr, addr_len, flags) - * - * Connect to a IrDA device - * - * The main difference with a "standard" connect is that with IrDA we need - * to resolve the service name into a TSAP selector (in TCP, port number - * doesn't have to be resolved). - * Because of this service name resolution, we can offer "auto-connect", - * where we connect to a service without specifying a destination address. - * - * Note : by consulting "errno", the user space caller may learn the cause - * of the failure. Most of them are visible in the function, others may come - * from subroutines called and are listed here : - * o EBUSY : already processing a connect - * o EHOSTUNREACH : bad addr->sir_addr argument - * o EADDRNOTAVAIL : bad addr->sir_name argument - * o ENOTUNIQ : more than one node has addr->sir_name (auto-connect) - * o ENETUNREACH : no node found on the network (auto-connect) - */ -static int irda_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) -{ - struct sock *sk = sock->sk; - struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr; - struct irda_sock *self = irda_sk(sk); - int err; - - pr_debug("%s(%p)\n", __func__, self); - - lock_sock(sk); - /* Don't allow connect for Ultra sockets */ - err = -ESOCKTNOSUPPORT; - if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA)) - goto out; - - if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { - sock->state = SS_CONNECTED; - err = 0; - goto out; /* Connect completed during a ERESTARTSYS event */ - } - - if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { - sock->state = SS_UNCONNECTED; - err = -ECONNREFUSED; - goto out; - } - - err = -EISCONN; /* No reconnect on a seqpacket socket */ - if (sk->sk_state == TCP_ESTABLISHED) - goto out; - - sk->sk_state = TCP_CLOSE; - sock->state = SS_UNCONNECTED; - - err = -EINVAL; - if (addr_len != sizeof(struct sockaddr_irda)) - goto out; - - /* Check if user supplied any destination device address */ - if ((!addr->sir_addr) || (addr->sir_addr == DEV_ADDR_ANY)) { - /* Try to find one suitable */ - err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name); - if (err) { - pr_debug("%s(), auto-connect failed!\n", __func__); - goto out; - } - } else { - /* Use the one provided by the user */ - self->daddr = addr->sir_addr; - pr_debug("%s(), daddr = %08x\n", __func__, self->daddr); - - /* If we don't have a valid service name, we assume the - * user want to connect on a specific LSAP. Prevent - * the use of invalid LSAPs (IrLMP 1.1 p10). Jean II */ - if((addr->sir_name[0] != '\0') || - (addr->sir_lsap_sel >= 0x70)) { - /* Query remote LM-IAS using service name */ - err = irda_find_lsap_sel(self, addr->sir_name); - if (err) { - pr_debug("%s(), connect failed!\n", __func__); - goto out; - } - } else { - /* Directly connect to the remote LSAP - * specified by the sir_lsap field. - * Please use with caution, in IrDA LSAPs are - * dynamic and there is no "well-known" LSAP. */ - self->dtsap_sel = addr->sir_lsap_sel; - } - } - - /* Check if we have opened a local TSAP */ - if (!self->tsap) { - err = irda_open_tsap(self, LSAP_ANY, addr->sir_name); - if (err) - goto out; - } - - /* Move to connecting socket, start sending Connect Requests */ - sock->state = SS_CONNECTING; - sk->sk_state = TCP_SYN_SENT; - - /* Connect to remote device */ - err = irttp_connect_request(self->tsap, self->dtsap_sel, - self->saddr, self->daddr, NULL, - self->max_sdu_size_rx, NULL); - if (err) { - pr_debug("%s(), connect failed!\n", __func__); - goto out; - } - - /* Now the loop */ - err = -EINPROGRESS; - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) - goto out; - - err = -ERESTARTSYS; - if (wait_event_interruptible(*(sk_sleep(sk)), - (sk->sk_state != TCP_SYN_SENT))) - goto out; - - if (sk->sk_state != TCP_ESTABLISHED) { - sock->state = SS_UNCONNECTED; - err = sock_error(sk); - if (!err) - err = -ECONNRESET; - goto out; - } - - sock->state = SS_CONNECTED; - - /* At this point, IrLMP has assigned our source address */ - self->saddr = irttp_get_saddr(self->tsap); - err = 0; -out: - release_sock(sk); - return err; -} - -static struct proto irda_proto = { - .name = "IRDA", - .owner = THIS_MODULE, - .obj_size = sizeof(struct irda_sock), -}; - -/* - * Function irda_create (sock, protocol) - * - * Create IrDA socket - * - */ -static int irda_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct sock *sk; - struct irda_sock *self; - - if (protocol < 0 || protocol > SK_PROTOCOL_MAX) - return -EINVAL; - - if (net != &init_net) - return -EAFNOSUPPORT; - - /* Check for valid socket type */ - switch (sock->type) { - case SOCK_STREAM: /* For TTP connections with SAR disabled */ - case SOCK_SEQPACKET: /* For TTP connections with SAR enabled */ - case SOCK_DGRAM: /* For TTP Unitdata or LMP Ultra transfers */ - break; - default: - return -ESOCKTNOSUPPORT; - } - - /* Allocate networking socket */ - sk = sk_alloc(net, PF_IRDA, GFP_KERNEL, &irda_proto, kern); - if (sk == NULL) - return -ENOMEM; - - self = irda_sk(sk); - pr_debug("%s() : self is %p\n", __func__, self); - - init_waitqueue_head(&self->query_wait); - - switch (sock->type) { - case SOCK_STREAM: - sock->ops = &irda_stream_ops; - self->max_sdu_size_rx = TTP_SAR_DISABLE; - break; - case SOCK_SEQPACKET: - sock->ops = &irda_seqpacket_ops; - self->max_sdu_size_rx = TTP_SAR_UNBOUND; - break; - case SOCK_DGRAM: - switch (protocol) { -#ifdef CONFIG_IRDA_ULTRA - case IRDAPROTO_ULTRA: - sock->ops = &irda_ultra_ops; - /* Initialise now, because we may send on unbound - * sockets. Jean II */ - self->max_data_size = ULTRA_MAX_DATA - LMP_PID_HEADER; - self->max_header_size = IRDA_MAX_HEADER + LMP_PID_HEADER; - break; -#endif /* CONFIG_IRDA_ULTRA */ - case IRDAPROTO_UNITDATA: - sock->ops = &irda_dgram_ops; - /* We let Unitdata conn. be like seqpack conn. */ - self->max_sdu_size_rx = TTP_SAR_UNBOUND; - break; - default: - sk_free(sk); - return -ESOCKTNOSUPPORT; - } - break; - default: - sk_free(sk); - return -ESOCKTNOSUPPORT; - } - - /* Initialise networking socket struct */ - sock_init_data(sock, sk); /* Note : set sk->sk_refcnt to 1 */ - sk->sk_family = PF_IRDA; - sk->sk_protocol = protocol; - - /* Register as a client with IrLMP */ - self->ckey = irlmp_register_client(0, NULL, NULL, NULL); - self->mask.word = 0xffff; - self->rx_flow = self->tx_flow = FLOW_START; - self->nslots = DISCOVERY_DEFAULT_SLOTS; - self->daddr = DEV_ADDR_ANY; /* Until we get connected */ - self->saddr = 0x0; /* so IrLMP assign us any link */ - return 0; -} - -/* - * Function irda_destroy_socket (self) - * - * Destroy socket - * - */ -static void irda_destroy_socket(struct irda_sock *self) -{ - pr_debug("%s(%p)\n", __func__, self); - - /* Unregister with IrLMP */ - irlmp_unregister_client(self->ckey); - irlmp_unregister_service(self->skey); - - /* Unregister with LM-IAS */ - if (self->ias_obj) { - irias_delete_object(self->ias_obj); - self->ias_obj = NULL; - } - - if (self->iriap) { - iriap_close(self->iriap); - self->iriap = NULL; - } - - if (self->tsap) { - irttp_disconnect_request(self->tsap, NULL, P_NORMAL); - irttp_close_tsap(self->tsap); - self->tsap = NULL; - } -#ifdef CONFIG_IRDA_ULTRA - if (self->lsap) { - irlmp_close_lsap(self->lsap); - self->lsap = NULL; - } -#endif /* CONFIG_IRDA_ULTRA */ -} - -/* - * Function irda_release (sock) - */ -static int irda_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (sk == NULL) - return 0; - - lock_sock(sk); - sk->sk_state = TCP_CLOSE; - sk->sk_shutdown |= SEND_SHUTDOWN; - sk->sk_state_change(sk); - - /* Destroy IrDA socket */ - irda_destroy_socket(irda_sk(sk)); - - sock_orphan(sk); - sock->sk = NULL; - release_sock(sk); - - /* Purge queues (see sock_init_data()) */ - skb_queue_purge(&sk->sk_receive_queue); - - /* Destroy networking socket if we are the last reference on it, - * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */ - sock_put(sk); - - /* Notes on socket locking and deallocation... - Jean II - * In theory we should put pairs of sock_hold() / sock_put() to - * prevent the socket to be destroyed whenever there is an - * outstanding request or outstanding incoming packet or event. - * - * 1) This may include IAS request, both in connect and getsockopt. - * Unfortunately, the situation is a bit more messy than it looks, - * because we close iriap and kfree(self) above. - * - * 2) This may include selective discovery in getsockopt. - * Same stuff as above, irlmp registration and self are gone. - * - * Probably 1 and 2 may not matter, because it's all triggered - * by a process and the socket layer already prevent the - * socket to go away while a process is holding it, through - * sockfd_put() and fput()... - * - * 3) This may include deferred TSAP closure. In particular, - * we may receive a late irda_disconnect_indication() - * Fortunately, (tsap_cb *)->close_pend should protect us - * from that. - * - * I did some testing on SMP, and it looks solid. And the socket - * memory leak is now gone... - Jean II - */ - - return 0; -} - -/* - * Function irda_sendmsg (sock, msg, len) - * - * Send message down to TinyTP. This function is used for both STREAM and - * SEQPACK services. This is possible since it forces the client to - * fragment the message if necessary - */ -static int irda_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) -{ - struct sock *sk = sock->sk; - struct irda_sock *self; - struct sk_buff *skb; - int err = -EPIPE; - - pr_debug("%s(), len=%zd\n", __func__, len); - - /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ - if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT | - MSG_NOSIGNAL)) { - return -EINVAL; - } - - lock_sock(sk); - - if (sk->sk_shutdown & SEND_SHUTDOWN) - goto out_err; - - if (sk->sk_state != TCP_ESTABLISHED) { - err = -ENOTCONN; - goto out; - } - - self = irda_sk(sk); - - /* Check if IrTTP is wants us to slow down */ - - if (wait_event_interruptible(*(sk_sleep(sk)), - (self->tx_flow != FLOW_STOP || sk->sk_state != TCP_ESTABLISHED))) { - err = -ERESTARTSYS; - goto out; - } - - /* Check if we are still connected */ - if (sk->sk_state != TCP_ESTABLISHED) { - err = -ENOTCONN; - goto out; - } - - /* Check that we don't send out too big frames */ - if (len > self->max_data_size) { - pr_debug("%s(), Chopping frame from %zd to %d bytes!\n", - __func__, len, self->max_data_size); - len = self->max_data_size; - } - - skb = sock_alloc_send_skb(sk, len + self->max_header_size + 16, - msg->msg_flags & MSG_DONTWAIT, &err); - if (!skb) - goto out_err; - - skb_reserve(skb, self->max_header_size + 16); - skb_reset_transport_header(skb); - skb_put(skb, len); - err = memcpy_from_msg(skb_transport_header(skb), msg, len); - if (err) { - kfree_skb(skb); - goto out_err; - } - - /* - * Just send the message to TinyTP, and let it deal with possible - * errors. No need to duplicate all that here - */ - err = irttp_data_request(self->tsap, skb); - if (err) { - pr_debug("%s(), err=%d\n", __func__, err); - goto out_err; - } - - release_sock(sk); - /* Tell client how much data we actually sent */ - return len; - -out_err: - err = sk_stream_error(sk, msg->msg_flags, err); -out: - release_sock(sk); - return err; - -} - -/* - * Function irda_recvmsg_dgram (sock, msg, size, flags) - * - * Try to receive message and copy it to user. The frame is discarded - * after being read, regardless of how much the user actually read - */ -static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, - size_t size, int flags) -{ - struct sock *sk = sock->sk; - struct irda_sock *self = irda_sk(sk); - struct sk_buff *skb; - size_t copied; - int err; - - skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, - flags & MSG_DONTWAIT, &err); - if (!skb) - return err; - - skb_reset_transport_header(skb); - copied = skb->len; - - if (copied > size) { - pr_debug("%s(), Received truncated frame (%zd < %zd)!\n", - __func__, copied, size); - copied = size; - msg->msg_flags |= MSG_TRUNC; - } - skb_copy_datagram_msg(skb, 0, msg, copied); - - skb_free_datagram(sk, skb); - - /* - * Check if we have previously stopped IrTTP and we know - * have more free space in our rx_queue. If so tell IrTTP - * to start delivering frames again before our rx_queue gets - * empty - */ - if (self->rx_flow == FLOW_STOP) { - if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { - pr_debug("%s(), Starting IrTTP\n", __func__); - self->rx_flow = FLOW_START; - irttp_flow_request(self->tsap, FLOW_START); - } - } - - return copied; -} - -/* - * Function irda_recvmsg_stream (sock, msg, size, flags) - */ -static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, - size_t size, int flags) -{ - struct sock *sk = sock->sk; - struct irda_sock *self = irda_sk(sk); - int noblock = flags & MSG_DONTWAIT; - size_t copied = 0; - int target, err; - long timeo; - - if ((err = sock_error(sk)) < 0) - return err; - - if (sock->flags & __SO_ACCEPTCON) - return -EINVAL; - - err =-EOPNOTSUPP; - if (flags & MSG_OOB) - return -EOPNOTSUPP; - - err = 0; - target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); - timeo = sock_rcvtimeo(sk, noblock); - - do { - int chunk; - struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); - - if (skb == NULL) { - DEFINE_WAIT(wait); - err = 0; - - if (copied >= target) - break; - - prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - /* - * POSIX 1003.1g mandates this order. - */ - err = sock_error(sk); - if (err) - ; - else if (sk->sk_shutdown & RCV_SHUTDOWN) - ; - else if (noblock) - err = -EAGAIN; - else if (signal_pending(current)) - err = sock_intr_errno(timeo); - else if (sk->sk_state != TCP_ESTABLISHED) - err = -ENOTCONN; - else if (skb_peek(&sk->sk_receive_queue) == NULL) - /* Wait process until data arrives */ - schedule(); - - finish_wait(sk_sleep(sk), &wait); - - if (err) - return err; - if (sk->sk_shutdown & RCV_SHUTDOWN) - break; - - continue; - } - - chunk = min_t(unsigned int, skb->len, size); - if (memcpy_to_msg(msg, skb->data, chunk)) { - skb_queue_head(&sk->sk_receive_queue, skb); - if (copied == 0) - copied = -EFAULT; - break; - } - copied += chunk; - size -= chunk; - - /* Mark read part of skb as used */ - if (!(flags & MSG_PEEK)) { - skb_pull(skb, chunk); - - /* put the skb back if we didn't use it up.. */ - if (skb->len) { - pr_debug("%s(), back on q!\n", - __func__); - skb_queue_head(&sk->sk_receive_queue, skb); - break; - } - - kfree_skb(skb); - } else { - pr_debug("%s() questionable!?\n", __func__); - - /* put message back and return */ - skb_queue_head(&sk->sk_receive_queue, skb); - break; - } - } while (size); - - /* - * Check if we have previously stopped IrTTP and we know - * have more free space in our rx_queue. If so tell IrTTP - * to start delivering frames again before our rx_queue gets - * empty - */ - if (self->rx_flow == FLOW_STOP) { - if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { - pr_debug("%s(), Starting IrTTP\n", __func__); - self->rx_flow = FLOW_START; - irttp_flow_request(self->tsap, FLOW_START); - } - } - - return copied; -} - -/* - * Function irda_sendmsg_dgram (sock, msg, len) - * - * Send message down to TinyTP for the unreliable sequenced - * packet service... - * - */ -static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg, - size_t len) -{ - struct sock *sk = sock->sk; - struct irda_sock *self; - struct sk_buff *skb; - int err; - - pr_debug("%s(), len=%zd\n", __func__, len); - - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) - return -EINVAL; - - lock_sock(sk); - - if (sk->sk_shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 0); - err = -EPIPE; - goto out; - } - - err = -ENOTCONN; - if (sk->sk_state != TCP_ESTABLISHED) - goto out; - - self = irda_sk(sk); - - /* - * Check that we don't send out too big frames. This is an unreliable - * service, so we have no fragmentation and no coalescence - */ - if (len > self->max_data_size) { - pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n", - __func__, len, self->max_data_size); - len = self->max_data_size; - } - - skb = sock_alloc_send_skb(sk, len + self->max_header_size, - msg->msg_flags & MSG_DONTWAIT, &err); - err = -ENOBUFS; - if (!skb) - goto out; - - skb_reserve(skb, self->max_header_size); - skb_reset_transport_header(skb); - - pr_debug("%s(), appending user data\n", __func__); - skb_put(skb, len); - err = memcpy_from_msg(skb_transport_header(skb), msg, len); - if (err) { - kfree_skb(skb); - goto out; - } - - /* - * Just send the message to TinyTP, and let it deal with possible - * errors. No need to duplicate all that here - */ - err = irttp_udata_request(self->tsap, skb); - if (err) { - pr_debug("%s(), err=%d\n", __func__, err); - goto out; - } - - release_sock(sk); - return len; - -out: - release_sock(sk); - return err; -} - -/* - * Function irda_sendmsg_ultra (sock, msg, len) - * - * Send message down to IrLMP for the unreliable Ultra - * packet service... - */ -#ifdef CONFIG_IRDA_ULTRA -static int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg, - size_t len) -{ - struct sock *sk = sock->sk; - struct irda_sock *self; - __u8 pid = 0; - int bound = 0; - struct sk_buff *skb; - int err; - - pr_debug("%s(), len=%zd\n", __func__, len); - - err = -EINVAL; - if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) - return -EINVAL; - - lock_sock(sk); - - err = -EPIPE; - if (sk->sk_shutdown & SEND_SHUTDOWN) { - send_sig(SIGPIPE, current, 0); - goto out; - } - - self = irda_sk(sk); - - /* Check if an address was specified with sendto. Jean II */ - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_irda *, addr, msg->msg_name); - err = -EINVAL; - /* Check address, extract pid. Jean II */ - if (msg->msg_namelen < sizeof(*addr)) - goto out; - if (addr->sir_family != AF_IRDA) - goto out; - - pid = addr->sir_lsap_sel; - if (pid & 0x80) { - pr_debug("%s(), extension in PID not supp!\n", - __func__); - err = -EOPNOTSUPP; - goto out; - } - } else { - /* Check that the socket is properly bound to an Ultra - * port. Jean II */ - if ((self->lsap == NULL) || - (sk->sk_state != TCP_ESTABLISHED)) { - pr_debug("%s(), socket not bound to Ultra PID.\n", - __func__); - err = -ENOTCONN; - goto out; - } - /* Use PID from socket */ - bound = 1; - } - - /* - * Check that we don't send out too big frames. This is an unreliable - * service, so we have no fragmentation and no coalescence - */ - if (len > self->max_data_size) { - pr_debug("%s(), Warning too much data! Chopping frame from %zd to %d bytes!\n", - __func__, len, self->max_data_size); - len = self->max_data_size; - } - - skb = sock_alloc_send_skb(sk, len + self->max_header_size, - msg->msg_flags & MSG_DONTWAIT, &err); - err = -ENOBUFS; - if (!skb) - goto out; - - skb_reserve(skb, self->max_header_size); - skb_reset_transport_header(skb); - - pr_debug("%s(), appending user data\n", __func__); - skb_put(skb, len); - err = memcpy_from_msg(skb_transport_header(skb), msg, len); - if (err) { - kfree_skb(skb); - goto out; - } - - err = irlmp_connless_data_request((bound ? self->lsap : NULL), - skb, pid); - if (err) - pr_debug("%s(), err=%d\n", __func__, err); -out: - release_sock(sk); - return err ? : len; -} -#endif /* CONFIG_IRDA_ULTRA */ - -/* - * Function irda_shutdown (sk, how) - */ -static int irda_shutdown(struct socket *sock, int how) -{ - struct sock *sk = sock->sk; - struct irda_sock *self = irda_sk(sk); - - pr_debug("%s(%p)\n", __func__, self); - - lock_sock(sk); - - sk->sk_state = TCP_CLOSE; - sk->sk_shutdown |= SEND_SHUTDOWN; - sk->sk_state_change(sk); - - if (self->iriap) { - iriap_close(self->iriap); - self->iriap = NULL; - } - - if (self->tsap) { - irttp_disconnect_request(self->tsap, NULL, P_NORMAL); - irttp_close_tsap(self->tsap); - self->tsap = NULL; - } - - /* A few cleanup so the socket look as good as new... */ - self->rx_flow = self->tx_flow = FLOW_START; /* needed ??? */ - self->daddr = DEV_ADDR_ANY; /* Until we get re-connected */ - self->saddr = 0x0; /* so IrLMP assign us any link */ - - release_sock(sk); - - return 0; -} - -/* - * Function irda_poll (file, sock, wait) - */ -static __poll_t irda_poll(struct file * file, struct socket *sock, - poll_table *wait) -{ - struct sock *sk = sock->sk; - struct irda_sock *self = irda_sk(sk); - __poll_t mask; - - poll_wait(file, sk_sleep(sk), wait); - mask = 0; - - /* Exceptional events? */ - if (sk->sk_err) - mask |= EPOLLERR; - if (sk->sk_shutdown & RCV_SHUTDOWN) { - pr_debug("%s(), POLLHUP\n", __func__); - mask |= EPOLLHUP; - } - - /* Readable? */ - if (!skb_queue_empty(&sk->sk_receive_queue)) { - pr_debug("Socket is readable\n"); - mask |= EPOLLIN | EPOLLRDNORM; - } - - /* Connection-based need to check for termination and startup */ - switch (sk->sk_type) { - case SOCK_STREAM: - if (sk->sk_state == TCP_CLOSE) { - pr_debug("%s(), POLLHUP\n", __func__); - mask |= EPOLLHUP; - } - - if (sk->sk_state == TCP_ESTABLISHED) { - if ((self->tx_flow == FLOW_START) && - sock_writeable(sk)) - { - mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; - } - } - break; - case SOCK_SEQPACKET: - if ((self->tx_flow == FLOW_START) && - sock_writeable(sk)) - { - mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; - } - break; - case SOCK_DGRAM: - if (sock_writeable(sk)) - mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; - break; - default: - break; - } - - return mask; -} - -/* - * Function irda_ioctl (sock, cmd, arg) - */ -static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - int err; - - pr_debug("%s(), cmd=%#x\n", __func__, cmd); - - err = -EINVAL; - switch (cmd) { - case TIOCOUTQ: { - long amount; - - amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk); - if (amount < 0) - amount = 0; - err = put_user(amount, (unsigned int __user *)arg); - break; - } - - case TIOCINQ: { - struct sk_buff *skb; - long amount = 0L; - /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) - amount = skb->len; - err = put_user(amount, (unsigned int __user *)arg); - break; - } - - case SIOCGSTAMP: - if (sk != NULL) - err = sock_get_timestamp(sk, (struct timeval __user *)arg); - break; - - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - break; - default: - pr_debug("%s(), doing device ioctl!\n", __func__); - err = -ENOIOCTLCMD; - } - - return err; -} - -#ifdef CONFIG_COMPAT -/* - * Function irda_ioctl (sock, cmd, arg) - */ -static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - /* - * All IRDA's ioctl are standard ones. - */ - return -ENOIOCTLCMD; -} -#endif - -/* - * Function irda_setsockopt (sock, level, optname, optval, optlen) - * - * Set some options for the socket - * - */ -static int irda_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - struct irda_sock *self = irda_sk(sk); - struct irda_ias_set *ias_opt; - struct ias_object *ias_obj; - struct ias_attrib * ias_attr; /* Attribute in IAS object */ - int opt, free_ias = 0, err = 0; - - pr_debug("%s(%p)\n", __func__, self); - - if (level != SOL_IRLMP) - return -ENOPROTOOPT; - - lock_sock(sk); - - switch (optname) { - case IRLMP_IAS_SET: - /* The user want to add an attribute to an existing IAS object - * (in the IAS database) or to create a new object with this - * attribute. - * We first query IAS to know if the object exist, and then - * create the right attribute... - */ - - if (optlen != sizeof(struct irda_ias_set)) { - err = -EINVAL; - goto out; - } - - /* Copy query to the driver. */ - ias_opt = memdup_user(optval, optlen); - if (IS_ERR(ias_opt)) { - err = PTR_ERR(ias_opt); - goto out; - } - - /* Find the object we target. - * If the user gives us an empty string, we use the object - * associated with this socket. This will workaround - * duplicated class name - Jean II */ - if(ias_opt->irda_class_name[0] == '\0') { - if(self->ias_obj == NULL) { - kfree(ias_opt); - err = -EINVAL; - goto out; - } - ias_obj = self->ias_obj; - } else - ias_obj = irias_find_object(ias_opt->irda_class_name); - - /* Only ROOT can mess with the global IAS database. - * Users can only add attributes to the object associated - * with the socket they own - Jean II */ - if((!capable(CAP_NET_ADMIN)) && - ((ias_obj == NULL) || (ias_obj != self->ias_obj))) { - kfree(ias_opt); - err = -EPERM; - goto out; - } - - /* If the object doesn't exist, create it */ - if(ias_obj == (struct ias_object *) NULL) { - /* Create a new object */ - ias_obj = irias_new_object(ias_opt->irda_class_name, - jiffies); - if (ias_obj == NULL) { - kfree(ias_opt); - err = -ENOMEM; - goto out; - } - free_ias = 1; - } - - /* Do we have the attribute already ? */ - if(irias_find_attrib(ias_obj, ias_opt->irda_attrib_name)) { - kfree(ias_opt); - if (free_ias) { - kfree(ias_obj->name); - kfree(ias_obj); - } - err = -EINVAL; - goto out; - } - - /* Look at the type */ - switch(ias_opt->irda_attrib_type) { - case IAS_INTEGER: - /* Add an integer attribute */ - irias_add_integer_attrib( - ias_obj, - ias_opt->irda_attrib_name, - ias_opt->attribute.irda_attrib_int, - IAS_USER_ATTR); - break; - case IAS_OCT_SEQ: - /* Check length */ - if(ias_opt->attribute.irda_attrib_octet_seq.len > - IAS_MAX_OCTET_STRING) { - kfree(ias_opt); - if (free_ias) { - kfree(ias_obj->name); - kfree(ias_obj); - } - - err = -EINVAL; - goto out; - } - /* Add an octet sequence attribute */ - irias_add_octseq_attrib( - ias_obj, - ias_opt->irda_attrib_name, - ias_opt->attribute.irda_attrib_octet_seq.octet_seq, - ias_opt->attribute.irda_attrib_octet_seq.len, - IAS_USER_ATTR); - break; - case IAS_STRING: - /* Should check charset & co */ - /* Check length */ - /* The length is encoded in a __u8, and - * IAS_MAX_STRING == 256, so there is no way - * userspace can pass us a string too large. - * Jean II */ - /* NULL terminate the string (avoid troubles) */ - ias_opt->attribute.irda_attrib_string.string[ias_opt->attribute.irda_attrib_string.len] = '\0'; - /* Add a string attribute */ - irias_add_string_attrib( - ias_obj, - ias_opt->irda_attrib_name, - ias_opt->attribute.irda_attrib_string.string, - IAS_USER_ATTR); - break; - default : - kfree(ias_opt); - if (free_ias) { - kfree(ias_obj->name); - kfree(ias_obj); - } - err = -EINVAL; - goto out; - } - irias_insert_object(ias_obj); - kfree(ias_opt); - break; - case IRLMP_IAS_DEL: - /* The user want to delete an object from our local IAS - * database. We just need to query the IAS, check is the - * object is not owned by the kernel and delete it. - */ - - if (optlen != sizeof(struct irda_ias_set)) { - err = -EINVAL; - goto out; - } - - /* Copy query to the driver. */ - ias_opt = memdup_user(optval, optlen); - if (IS_ERR(ias_opt)) { - err = PTR_ERR(ias_opt); - goto out; - } - - /* Find the object we target. - * If the user gives us an empty string, we use the object - * associated with this socket. This will workaround - * duplicated class name - Jean II */ - if(ias_opt->irda_class_name[0] == '\0') - ias_obj = self->ias_obj; - else - ias_obj = irias_find_object(ias_opt->irda_class_name); - if(ias_obj == (struct ias_object *) NULL) { - kfree(ias_opt); - err = -EINVAL; - goto out; - } - - /* Only ROOT can mess with the global IAS database. - * Users can only del attributes from the object associated - * with the socket they own - Jean II */ - if((!capable(CAP_NET_ADMIN)) && - ((ias_obj == NULL) || (ias_obj != self->ias_obj))) { - kfree(ias_opt); - err = -EPERM; - goto out; - } - - /* Find the attribute (in the object) we target */ - ias_attr = irias_find_attrib(ias_obj, - ias_opt->irda_attrib_name); - if(ias_attr == (struct ias_attrib *) NULL) { - kfree(ias_opt); - err = -EINVAL; - goto out; - } - - /* Check is the user space own the object */ - if(ias_attr->value->owner != IAS_USER_ATTR) { - pr_debug("%s(), attempting to delete a kernel attribute\n", - __func__); - kfree(ias_opt); - err = -EPERM; - goto out; - } - - /* Remove the attribute (and maybe the object) */ - irias_delete_attrib(ias_obj, ias_attr, 1); - kfree(ias_opt); - break; - case IRLMP_MAX_SDU_SIZE: - if (optlen < sizeof(int)) { - err = -EINVAL; - goto out; - } - - if (get_user(opt, (int __user *)optval)) { - err = -EFAULT; - goto out; - } - - /* Only possible for a seqpacket service (TTP with SAR) */ - if (sk->sk_type != SOCK_SEQPACKET) { - pr_debug("%s(), setting max_sdu_size = %d\n", - __func__, opt); - self->max_sdu_size_rx = opt; - } else { - net_warn_ratelimited("%s: not allowed to set MAXSDUSIZE for this socket type!\n", - __func__); - err = -ENOPROTOOPT; - goto out; - } - break; - case IRLMP_HINTS_SET: - if (optlen < sizeof(int)) { - err = -EINVAL; - goto out; - } - - /* The input is really a (__u8 hints[2]), easier as an int */ - if (get_user(opt, (int __user *)optval)) { - err = -EFAULT; - goto out; - } - - /* Unregister any old registration */ - irlmp_unregister_service(self->skey); - - self->skey = irlmp_register_service((__u16) opt); - break; - case IRLMP_HINT_MASK_SET: - /* As opposed to the previous case which set the hint bits - * that we advertise, this one set the filter we use when - * making a discovery (nodes which don't match any hint - * bit in the mask are not reported). - */ - if (optlen < sizeof(int)) { - err = -EINVAL; - goto out; - } - - /* The input is really a (__u8 hints[2]), easier as an int */ - if (get_user(opt, (int __user *)optval)) { - err = -EFAULT; - goto out; - } - - /* Set the new hint mask */ - self->mask.word = (__u16) opt; - /* Mask out extension bits */ - self->mask.word &= 0x7f7f; - /* Check if no bits */ - if(!self->mask.word) - self->mask.word = 0xFFFF; - - break; - default: - err = -ENOPROTOOPT; - break; - } - -out: - release_sock(sk); - - return err; -} - -/* - * Function irda_extract_ias_value(ias_opt, ias_value) - * - * Translate internal IAS value structure to the user space representation - * - * The external representation of IAS values, as we exchange them with - * user space program is quite different from the internal representation, - * as stored in the IAS database (because we need a flat structure for - * crossing kernel boundary). - * This function transform the former in the latter. We also check - * that the value type is valid. - */ -static int irda_extract_ias_value(struct irda_ias_set *ias_opt, - struct ias_value *ias_value) -{ - /* Look at the type */ - switch (ias_value->type) { - case IAS_INTEGER: - /* Copy the integer */ - ias_opt->attribute.irda_attrib_int = ias_value->t.integer; - break; - case IAS_OCT_SEQ: - /* Set length */ - ias_opt->attribute.irda_attrib_octet_seq.len = ias_value->len; - /* Copy over */ - memcpy(ias_opt->attribute.irda_attrib_octet_seq.octet_seq, - ias_value->t.oct_seq, ias_value->len); - break; - case IAS_STRING: - /* Set length */ - ias_opt->attribute.irda_attrib_string.len = ias_value->len; - ias_opt->attribute.irda_attrib_string.charset = ias_value->charset; - /* Copy over */ - memcpy(ias_opt->attribute.irda_attrib_string.string, - ias_value->t.string, ias_value->len); - /* NULL terminate the string (avoid troubles) */ - ias_opt->attribute.irda_attrib_string.string[ias_value->len] = '\0'; - break; - case IAS_MISSING: - default : - return -EINVAL; - } - - /* Copy type over */ - ias_opt->irda_attrib_type = ias_value->type; - - return 0; -} - -/* - * Function irda_getsockopt (sock, level, optname, optval, optlen) - */ -static int irda_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - struct irda_sock *self = irda_sk(sk); - struct irda_device_list list = { 0 }; - struct irda_device_info *discoveries; - struct irda_ias_set * ias_opt; /* IAS get/query params */ - struct ias_object * ias_obj; /* Object in IAS */ - struct ias_attrib * ias_attr; /* Attribute in IAS object */ - int daddr = DEV_ADDR_ANY; /* Dest address for IAS queries */ - int val = 0; - int len = 0; - int err = 0; - int offset, total; - - pr_debug("%s(%p)\n", __func__, self); - - if (level != SOL_IRLMP) - return -ENOPROTOOPT; - - if (get_user(len, optlen)) - return -EFAULT; - - if(len < 0) - return -EINVAL; - - lock_sock(sk); - - switch (optname) { - case IRLMP_ENUMDEVICES: - - /* Offset to first device entry */ - offset = sizeof(struct irda_device_list) - - sizeof(struct irda_device_info); - - if (len < offset) { - err = -EINVAL; - goto out; - } - - /* Ask lmp for the current discovery log */ - discoveries = irlmp_get_discoveries(&list.len, self->mask.word, - self->nslots); - /* Check if the we got some results */ - if (discoveries == NULL) { - err = -EAGAIN; - goto out; /* Didn't find any devices */ - } - - /* Write total list length back to client */ - if (copy_to_user(optval, &list, offset)) - err = -EFAULT; - - /* Copy the list itself - watch for overflow */ - if (list.len > 2048) { - err = -EINVAL; - goto bed; - } - total = offset + (list.len * sizeof(struct irda_device_info)); - if (total > len) - total = len; - if (copy_to_user(optval+offset, discoveries, total - offset)) - err = -EFAULT; - - /* Write total number of bytes used back to client */ - if (put_user(total, optlen)) - err = -EFAULT; -bed: - /* Free up our buffer */ - kfree(discoveries); - break; - case IRLMP_MAX_SDU_SIZE: - val = self->max_data_size; - len = sizeof(int); - if (put_user(len, optlen)) { - err = -EFAULT; - goto out; - } - - if (copy_to_user(optval, &val, len)) { - err = -EFAULT; - goto out; - } - - break; - case IRLMP_IAS_GET: - /* The user want an object from our local IAS database. - * We just need to query the IAS and return the value - * that we found */ - - /* Check that the user has allocated the right space for us */ - if (len != sizeof(struct irda_ias_set)) { - err = -EINVAL; - goto out; - } - - /* Copy query to the driver. */ - ias_opt = memdup_user(optval, len); - if (IS_ERR(ias_opt)) { - err = PTR_ERR(ias_opt); - goto out; - } - - /* Find the object we target. - * If the user gives us an empty string, we use the object - * associated with this socket. This will workaround - * duplicated class name - Jean II */ - if(ias_opt->irda_class_name[0] == '\0') - ias_obj = self->ias_obj; - else - ias_obj = irias_find_object(ias_opt->irda_class_name); - if(ias_obj == (struct ias_object *) NULL) { - kfree(ias_opt); - err = -EINVAL; - goto out; - } - - /* Find the attribute (in the object) we target */ - ias_attr = irias_find_attrib(ias_obj, - ias_opt->irda_attrib_name); - if(ias_attr == (struct ias_attrib *) NULL) { - kfree(ias_opt); - err = -EINVAL; - goto out; - } - - /* Translate from internal to user structure */ - err = irda_extract_ias_value(ias_opt, ias_attr->value); - if(err) { - kfree(ias_opt); - goto out; - } - - /* Copy reply to the user */ - if (copy_to_user(optval, ias_opt, - sizeof(struct irda_ias_set))) { - kfree(ias_opt); - err = -EFAULT; - goto out; - } - /* Note : don't need to put optlen, we checked it */ - kfree(ias_opt); - break; - case IRLMP_IAS_QUERY: - /* The user want an object from a remote IAS database. - * We need to use IAP to query the remote database and - * then wait for the answer to come back. */ - - /* Check that the user has allocated the right space for us */ - if (len != sizeof(struct irda_ias_set)) { - err = -EINVAL; - goto out; - } - - /* Copy query to the driver. */ - ias_opt = memdup_user(optval, len); - if (IS_ERR(ias_opt)) { - err = PTR_ERR(ias_opt); - goto out; - } - - /* At this point, there are two cases... - * 1) the socket is connected - that's the easy case, we - * just query the device we are connected to... - * 2) the socket is not connected - the user doesn't want - * to connect and/or may not have a valid service name - * (so can't create a fake connection). In this case, - * we assume that the user pass us a valid destination - * address in the requesting structure... - */ - if(self->daddr != DEV_ADDR_ANY) { - /* We are connected - reuse known daddr */ - daddr = self->daddr; - } else { - /* We are not connected, we must specify a valid - * destination address */ - daddr = ias_opt->daddr; - if((!daddr) || (daddr == DEV_ADDR_ANY)) { - kfree(ias_opt); - err = -EINVAL; - goto out; - } - } - - /* Check that we can proceed with IAP */ - if (self->iriap) { - net_warn_ratelimited("%s: busy with a previous query\n", - __func__); - kfree(ias_opt); - err = -EBUSY; - goto out; - } - - self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - irda_getvalue_confirm); - - if (self->iriap == NULL) { - kfree(ias_opt); - err = -ENOMEM; - goto out; - } - - /* Treat unexpected wakeup as disconnect */ - self->errno = -EHOSTUNREACH; - - /* Query remote LM-IAS */ - iriap_getvaluebyclass_request(self->iriap, - self->saddr, daddr, - ias_opt->irda_class_name, - ias_opt->irda_attrib_name); - - /* Wait for answer, if not yet finished (or failed) */ - if (wait_event_interruptible(self->query_wait, - (self->iriap == NULL))) { - /* pending request uses copy of ias_opt-content - * we can free it regardless! */ - kfree(ias_opt); - /* Treat signals as disconnect */ - err = -EHOSTUNREACH; - goto out; - } - - /* Check what happened */ - if (self->errno) - { - kfree(ias_opt); - /* Requested object/attribute doesn't exist */ - if((self->errno == IAS_CLASS_UNKNOWN) || - (self->errno == IAS_ATTRIB_UNKNOWN)) - err = -EADDRNOTAVAIL; - else - err = -EHOSTUNREACH; - - goto out; - } - - /* Translate from internal to user structure */ - err = irda_extract_ias_value(ias_opt, self->ias_result); - if (self->ias_result) - irias_delete_value(self->ias_result); - if (err) { - kfree(ias_opt); - goto out; - } - - /* Copy reply to the user */ - if (copy_to_user(optval, ias_opt, - sizeof(struct irda_ias_set))) { - kfree(ias_opt); - err = -EFAULT; - goto out; - } - /* Note : don't need to put optlen, we checked it */ - kfree(ias_opt); - break; - case IRLMP_WAITDEVICE: - /* This function is just another way of seeing life ;-) - * IRLMP_ENUMDEVICES assumes that you have a static network, - * and that you just want to pick one of the devices present. - * On the other hand, in here we assume that no device is - * present and that at some point in the future a device will - * come into range. When this device arrive, we just wake - * up the caller, so that he has time to connect to it before - * the device goes away... - * Note : once the node has been discovered for more than a - * few second, it won't trigger this function, unless it - * goes away and come back changes its hint bits (so we - * might call it IRLMP_WAITNEWDEVICE). - */ - - /* Check that the user is passing us an int */ - if (len != sizeof(int)) { - err = -EINVAL; - goto out; - } - /* Get timeout in ms (max time we block the caller) */ - if (get_user(val, (int __user *)optval)) { - err = -EFAULT; - goto out; - } - - /* Tell IrLMP we want to be notified */ - irlmp_update_client(self->ckey, self->mask.word, - irda_selective_discovery_indication, - NULL, (void *) self); - - /* Do some discovery (and also return cached results) */ - irlmp_discovery_request(self->nslots); - - /* Wait until a node is discovered */ - if (!self->cachedaddr) { - pr_debug("%s(), nothing discovered yet, going to sleep...\n", - __func__); - - /* Set watchdog timer to expire in <val> ms. */ - self->errno = 0; - timer_setup(&self->watchdog, irda_discovery_timeout, 0); - mod_timer(&self->watchdog, - jiffies + msecs_to_jiffies(val)); - - /* Wait for IR-LMP to call us back */ - err = __wait_event_interruptible(self->query_wait, - (self->cachedaddr != 0 || self->errno == -ETIME)); - - /* If watchdog is still activated, kill it! */ - del_timer(&(self->watchdog)); - - pr_debug("%s(), ...waking up !\n", __func__); - - if (err != 0) - goto out; - } - else - pr_debug("%s(), found immediately !\n", - __func__); - - /* Tell IrLMP that we have been notified */ - irlmp_update_client(self->ckey, self->mask.word, - NULL, NULL, NULL); - - /* Check if the we got some results */ - if (!self->cachedaddr) { - err = -EAGAIN; /* Didn't find any devices */ - goto out; - } - daddr = self->cachedaddr; - /* Cleanup */ - self->cachedaddr = 0; - - /* We return the daddr of the device that trigger the - * wakeup. As irlmp pass us only the new devices, we - * are sure that it's not an old device. - * If the user want more details, he should query - * the whole discovery log and pick one device... - */ - if (put_user(daddr, (int __user *)optval)) { - err = -EFAULT; - goto out; - } - - break; - default: - err = -ENOPROTOOPT; - } - -out: - - release_sock(sk); - - return err; -} - -static const struct net_proto_family irda_family_ops = { - .family = PF_IRDA, - .create = irda_create, - .owner = THIS_MODULE, -}; - -static const struct proto_ops irda_stream_ops = { - .family = PF_IRDA, - .owner = THIS_MODULE, - .release = irda_release, - .bind = irda_bind, - .connect = irda_connect, - .socketpair = sock_no_socketpair, - .accept = irda_accept, - .getname = irda_getname, - .poll = irda_poll, - .ioctl = irda_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = irda_compat_ioctl, -#endif - .listen = irda_listen, - .shutdown = irda_shutdown, - .setsockopt = irda_setsockopt, - .getsockopt = irda_getsockopt, - .sendmsg = irda_sendmsg, - .recvmsg = irda_recvmsg_stream, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -}; - -static const struct proto_ops irda_seqpacket_ops = { - .family = PF_IRDA, - .owner = THIS_MODULE, - .release = irda_release, - .bind = irda_bind, - .connect = irda_connect, - .socketpair = sock_no_socketpair, - .accept = irda_accept, - .getname = irda_getname, - .poll = datagram_poll, - .ioctl = irda_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = irda_compat_ioctl, -#endif - .listen = irda_listen, - .shutdown = irda_shutdown, - .setsockopt = irda_setsockopt, - .getsockopt = irda_getsockopt, - .sendmsg = irda_sendmsg, - .recvmsg = irda_recvmsg_dgram, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -}; - -static const struct proto_ops irda_dgram_ops = { - .family = PF_IRDA, - .owner = THIS_MODULE, - .release = irda_release, - .bind = irda_bind, - .connect = irda_connect, - .socketpair = sock_no_socketpair, - .accept = irda_accept, - .getname = irda_getname, - .poll = datagram_poll, - .ioctl = irda_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = irda_compat_ioctl, -#endif - .listen = irda_listen, - .shutdown = irda_shutdown, - .setsockopt = irda_setsockopt, - .getsockopt = irda_getsockopt, - .sendmsg = irda_sendmsg_dgram, - .recvmsg = irda_recvmsg_dgram, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -}; - -#ifdef CONFIG_IRDA_ULTRA -static const struct proto_ops irda_ultra_ops = { - .family = PF_IRDA, - .owner = THIS_MODULE, - .release = irda_release, - .bind = irda_bind, - .connect = sock_no_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = irda_getname, - .poll = datagram_poll, - .ioctl = irda_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = irda_compat_ioctl, -#endif - .listen = sock_no_listen, - .shutdown = irda_shutdown, - .setsockopt = irda_setsockopt, - .getsockopt = irda_getsockopt, - .sendmsg = irda_sendmsg_ultra, - .recvmsg = irda_recvmsg_dgram, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -}; -#endif /* CONFIG_IRDA_ULTRA */ - -/* - * Function irsock_init (pro) - * - * Initialize IrDA protocol - * - */ -int __init irsock_init(void) -{ - int rc = proto_register(&irda_proto, 0); - - if (rc == 0) - rc = sock_register(&irda_family_ops); - - return rc; -} - -/* - * Function irsock_cleanup (void) - * - * Remove IrDA protocol - * - */ -void irsock_cleanup(void) -{ - sock_unregister(PF_IRDA); - proto_unregister(&irda_proto); -} diff --git a/drivers/staging/irda/net/discovery.c b/drivers/staging/irda/net/discovery.c deleted file mode 100644 index 1e54954a4081..000000000000 --- a/drivers/staging/irda/net/discovery.c +++ /dev/null @@ -1,417 +0,0 @@ -/********************************************************************* - * - * Filename: discovery.c - * Version: 0.1 - * Description: Routines for handling discoveries at the IrLMP layer - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Apr 6 15:33:50 1999 - * Modified at: Sat Oct 9 17:11:31 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Modified at: Fri May 28 3:11 CST 1999 - * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/string.h> -#include <linux/socket.h> -#include <linux/fs.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <linux/export.h> - -#include <net/irda/irda.h> -#include <net/irda/irlmp.h> - -#include <net/irda/discovery.h> - -#include <asm/unaligned.h> - -/* - * Function irlmp_add_discovery (cachelog, discovery) - * - * Add a new discovery to the cachelog, and remove any old discoveries - * from the same device - * - * Note : we try to preserve the time this device was *first* discovered - * (as opposed to the time of last discovery used for cleanup). This is - * used by clients waiting for discovery events to tell if the device - * discovered is "new" or just the same old one. They can't rely there - * on a binary flag (new/old), because not all discovery events are - * propagated to them, and they might not always listen, so they would - * miss some new devices popping up... - * Jean II - */ -void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new) -{ - discovery_t *discovery, *node; - unsigned long flags; - - /* Set time of first discovery if node is new (see below) */ - new->firststamp = new->timestamp; - - spin_lock_irqsave(&cachelog->hb_spinlock, flags); - - /* - * Remove all discoveries of devices that has previously been - * discovered on the same link with the same name (info), or the - * same daddr. We do this since some devices (mostly PDAs) change - * their device address between every discovery. - */ - discovery = (discovery_t *) hashbin_get_first(cachelog); - while (discovery != NULL ) { - node = discovery; - - /* Be sure to stay one item ahead */ - discovery = (discovery_t *) hashbin_get_next(cachelog); - - if ((node->data.saddr == new->data.saddr) && - ((node->data.daddr == new->data.daddr) || - (strcmp(node->data.info, new->data.info) == 0))) - { - /* This discovery is a previous discovery - * from the same device, so just remove it - */ - hashbin_remove_this(cachelog, (irda_queue_t *) node); - /* Check if hints bits are unchanged */ - if (get_unaligned((__u16 *)node->data.hints) == get_unaligned((__u16 *)new->data.hints)) - /* Set time of first discovery for this node */ - new->firststamp = node->firststamp; - kfree(node); - } - } - - /* Insert the new and updated version */ - hashbin_insert(cachelog, (irda_queue_t *) new, new->data.daddr, NULL); - - spin_unlock_irqrestore(&cachelog->hb_spinlock, flags); -} - -/* - * Function irlmp_add_discovery_log (cachelog, log) - * - * Merge a disovery log into the cachelog. - * - */ -void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log) -{ - discovery_t *discovery; - - /* - * If log is missing this means that IrLAP was unable to perform the - * discovery, so restart discovery again with just the half timeout - * of the normal one. - */ - /* Well... It means that there was nobody out there - Jean II */ - if (log == NULL) { - /* irlmp_start_discovery_timer(irlmp, 150); */ - return; - } - - /* - * Locking : we are the only owner of this discovery log, so - * no need to lock it. - * We just need to lock the global log in irlmp_add_discovery(). - */ - discovery = (discovery_t *) hashbin_remove_first(log); - while (discovery != NULL) { - irlmp_add_discovery(cachelog, discovery); - - discovery = (discovery_t *) hashbin_remove_first(log); - } - - /* Delete the now empty log */ - hashbin_delete(log, (FREE_FUNC) kfree); -} - -/* - * Function irlmp_expire_discoveries (log, saddr, force) - * - * Go through all discoveries and expire all that has stayed too long - * - * Note : this assume that IrLAP won't change its saddr, which - * currently is a valid assumption... - */ -void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force) -{ - discovery_t * discovery; - discovery_t * curr; - unsigned long flags; - discinfo_t * buffer = NULL; - int n; /* Size of the full log */ - int i = 0; /* How many we expired */ - - IRDA_ASSERT(log != NULL, return;); - spin_lock_irqsave(&log->hb_spinlock, flags); - - discovery = (discovery_t *) hashbin_get_first(log); - while (discovery != NULL) { - /* Be sure to be one item ahead */ - curr = discovery; - discovery = (discovery_t *) hashbin_get_next(log); - - /* Test if it's time to expire this discovery */ - if ((curr->data.saddr == saddr) && - (force || - ((jiffies - curr->timestamp) > DISCOVERY_EXPIRE_TIMEOUT))) - { - /* Create buffer as needed. - * As this function get called a lot and most time - * we don't have anything to put in the log (we are - * quite picky), we can save a lot of overhead - * by not calling kmalloc. Jean II */ - if(buffer == NULL) { - /* Create the client specific buffer */ - n = HASHBIN_GET_SIZE(log); - buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); - if (!buffer) { - spin_unlock_irqrestore(&log->hb_spinlock, flags); - return; - } - - } - - /* Copy discovery information */ - memcpy(&(buffer[i]), &(curr->data), - sizeof(discinfo_t)); - i++; - - /* Remove it from the log */ - curr = hashbin_remove_this(log, (irda_queue_t *) curr); - kfree(curr); - } - } - - /* Drop the spinlock before calling the higher layers, as - * we can't guarantee they won't call us back and create a - * deadlock. We will work on our own private data, so we - * don't care to be interrupted. - Jean II */ - spin_unlock_irqrestore(&log->hb_spinlock, flags); - - if(buffer == NULL) - return; - - /* Tell IrLMP and registered clients about it */ - irlmp_discovery_expiry(buffer, i); - - /* Free up our buffer */ - kfree(buffer); -} - -#if 0 -/* - * Function irlmp_dump_discoveries (log) - * - * Print out all discoveries in log - * - */ -void irlmp_dump_discoveries(hashbin_t *log) -{ - discovery_t *discovery; - - IRDA_ASSERT(log != NULL, return;); - - discovery = (discovery_t *) hashbin_get_first(log); - while (discovery != NULL) { - pr_debug("Discovery:\n"); - pr_debug(" daddr=%08x\n", discovery->data.daddr); - pr_debug(" saddr=%08x\n", discovery->data.saddr); - pr_debug(" nickname=%s\n", discovery->data.info); - - discovery = (discovery_t *) hashbin_get_next(log); - } -} -#endif - -/* - * Function irlmp_copy_discoveries (log, pn, mask) - * - * Copy all discoveries in a buffer - * - * This function implement a safe way for lmp clients to access the - * discovery log. The basic problem is that we don't want the log - * to change (add/remove) while the client is reading it. If the - * lmp client manipulate directly the hashbin, he is sure to get - * into troubles... - * The idea is that we copy all the current discovery log in a buffer - * which is specific to the client and pass this copy to him. As we - * do this operation with the spinlock grabbed, we are safe... - * Note : we don't want those clients to grab the spinlock, because - * we have no control on how long they will hold it... - * Note : we choose to copy the log in "struct irda_device_info" to - * save space... - * Note : the client must kfree himself() the log... - * Jean II - */ -struct irda_device_info *irlmp_copy_discoveries(hashbin_t *log, int *pn, - __u16 mask, int old_entries) -{ - discovery_t * discovery; - unsigned long flags; - discinfo_t * buffer = NULL; - int j_timeout = (sysctl_discovery_timeout * HZ); - int n; /* Size of the full log */ - int i = 0; /* How many we picked */ - - IRDA_ASSERT(pn != NULL, return NULL;); - IRDA_ASSERT(log != NULL, return NULL;); - - /* Save spin lock */ - spin_lock_irqsave(&log->hb_spinlock, flags); - - discovery = (discovery_t *) hashbin_get_first(log); - while (discovery != NULL) { - /* Mask out the ones we don't want : - * We want to match the discovery mask, and to get only - * the most recent one (unless we want old ones) */ - if ((get_unaligned((__u16 *)discovery->data.hints) & mask) && - ((old_entries) || - ((jiffies - discovery->firststamp) < j_timeout))) { - /* Create buffer as needed. - * As this function get called a lot and most time - * we don't have anything to put in the log (we are - * quite picky), we can save a lot of overhead - * by not calling kmalloc. Jean II */ - if(buffer == NULL) { - /* Create the client specific buffer */ - n = HASHBIN_GET_SIZE(log); - buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC); - if (!buffer) { - spin_unlock_irqrestore(&log->hb_spinlock, flags); - return NULL; - } - - } - - /* Copy discovery information */ - memcpy(&(buffer[i]), &(discovery->data), - sizeof(discinfo_t)); - i++; - } - discovery = (discovery_t *) hashbin_get_next(log); - } - - spin_unlock_irqrestore(&log->hb_spinlock, flags); - - /* Get the actual number of device in the buffer and return */ - *pn = i; - return buffer; -} - -#ifdef CONFIG_PROC_FS -static inline discovery_t *discovery_seq_idx(loff_t pos) - -{ - discovery_t *discovery; - - for (discovery = (discovery_t *) hashbin_get_first(irlmp->cachelog); - discovery != NULL; - discovery = (discovery_t *) hashbin_get_next(irlmp->cachelog)) { - if (pos-- == 0) - break; - } - - return discovery; -} - -static void *discovery_seq_start(struct seq_file *seq, loff_t *pos) -{ - spin_lock_irq(&irlmp->cachelog->hb_spinlock); - return *pos ? discovery_seq_idx(*pos - 1) : SEQ_START_TOKEN; -} - -static void *discovery_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return (v == SEQ_START_TOKEN) - ? (void *) hashbin_get_first(irlmp->cachelog) - : (void *) hashbin_get_next(irlmp->cachelog); -} - -static void discovery_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_irq(&irlmp->cachelog->hb_spinlock); -} - -static int discovery_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_puts(seq, "IrLMP: Discovery log:\n\n"); - else { - const discovery_t *discovery = v; - - seq_printf(seq, "nickname: %s, hint: 0x%02x%02x", - discovery->data.info, - discovery->data.hints[0], - discovery->data.hints[1]); -#if 0 - if ( discovery->data.hints[0] & HINT_PNP) - seq_puts(seq, "PnP Compatible "); - if ( discovery->data.hints[0] & HINT_PDA) - seq_puts(seq, "PDA/Palmtop "); - if ( discovery->data.hints[0] & HINT_COMPUTER) - seq_puts(seq, "Computer "); - if ( discovery->data.hints[0] & HINT_PRINTER) - seq_puts(seq, "Printer "); - if ( discovery->data.hints[0] & HINT_MODEM) - seq_puts(seq, "Modem "); - if ( discovery->data.hints[0] & HINT_FAX) - seq_puts(seq, "Fax "); - if ( discovery->data.hints[0] & HINT_LAN) - seq_puts(seq, "LAN Access "); - - if ( discovery->data.hints[1] & HINT_TELEPHONY) - seq_puts(seq, "Telephony "); - if ( discovery->data.hints[1] & HINT_FILE_SERVER) - seq_puts(seq, "File Server "); - if ( discovery->data.hints[1] & HINT_COMM) - seq_puts(seq, "IrCOMM "); - if ( discovery->data.hints[1] & HINT_OBEX) - seq_puts(seq, "IrOBEX "); -#endif - seq_printf(seq,", saddr: 0x%08x, daddr: 0x%08x\n\n", - discovery->data.saddr, - discovery->data.daddr); - - seq_putc(seq, '\n'); - } - return 0; -} - -static const struct seq_operations discovery_seq_ops = { - .start = discovery_seq_start, - .next = discovery_seq_next, - .stop = discovery_seq_stop, - .show = discovery_seq_show, -}; - -static int discovery_seq_open(struct inode *inode, struct file *file) -{ - IRDA_ASSERT(irlmp != NULL, return -EINVAL;); - - return seq_open(file, &discovery_seq_ops); -} - -const struct file_operations discovery_seq_fops = { - .owner = THIS_MODULE, - .open = discovery_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif diff --git a/drivers/staging/irda/net/ircomm/Kconfig b/drivers/staging/irda/net/ircomm/Kconfig deleted file mode 100644 index 19492c1707b7..000000000000 --- a/drivers/staging/irda/net/ircomm/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config IRCOMM - tristate "IrCOMM protocol" - depends on IRDA && TTY - help - Say Y here if you want to build support for the IrCOMM protocol. - To compile it as modules, choose M here: the modules will be - called ircomm and ircomm_tty. - IrCOMM implements serial port emulation, and makes it possible to - use all existing applications that understands TTY's with an - infrared link. Thus you should be able to use application like PPP, - minicom and others. - diff --git a/drivers/staging/irda/net/ircomm/Makefile b/drivers/staging/irda/net/ircomm/Makefile deleted file mode 100644 index ab23b5ba7e33..000000000000 --- a/drivers/staging/irda/net/ircomm/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the Linux IrDA IrCOMM protocol layer. -# - -obj-$(CONFIG_IRCOMM) += ircomm.o ircomm-tty.o - -ircomm-y := ircomm_core.o ircomm_event.o ircomm_lmp.o ircomm_ttp.o -ircomm-tty-y := ircomm_tty.o ircomm_tty_attach.o ircomm_tty_ioctl.o ircomm_param.o diff --git a/drivers/staging/irda/net/ircomm/ircomm_core.c b/drivers/staging/irda/net/ircomm/ircomm_core.c deleted file mode 100644 index 3af219545f6d..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_core.c +++ /dev/null @@ -1,563 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_core.c - * Version: 1.0 - * Description: IrCOMM service interface - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Jun 6 20:37:34 1999 - * Modified at: Tue Dec 21 13:26:41 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/init.h> -#include <linux/slab.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> -#include <net/irda/irlmp.h> -#include <net/irda/iriap.h> -#include <net/irda/irttp.h> -#include <net/irda/irias_object.h> - -#include <net/irda/ircomm_event.h> -#include <net/irda/ircomm_lmp.h> -#include <net/irda/ircomm_ttp.h> -#include <net/irda/ircomm_param.h> -#include <net/irda/ircomm_core.h> - -static int __ircomm_close(struct ircomm_cb *self); -static void ircomm_control_indication(struct ircomm_cb *self, - struct sk_buff *skb, int clen); - -#ifdef CONFIG_PROC_FS -extern struct proc_dir_entry *proc_irda; -static int ircomm_seq_open(struct inode *, struct file *); - -static const struct file_operations ircomm_proc_fops = { - .owner = THIS_MODULE, - .open = ircomm_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif /* CONFIG_PROC_FS */ - -hashbin_t *ircomm = NULL; - -static int __init ircomm_init(void) -{ - ircomm = hashbin_new(HB_LOCK); - if (ircomm == NULL) { - net_err_ratelimited("%s(), can't allocate hashbin!\n", - __func__); - return -ENOMEM; - } - -#ifdef CONFIG_PROC_FS - { struct proc_dir_entry *ent; - ent = proc_create("ircomm", 0, proc_irda, &ircomm_proc_fops); - if (!ent) { - printk(KERN_ERR "ircomm_init: can't create /proc entry!\n"); - return -ENODEV; - } - } -#endif /* CONFIG_PROC_FS */ - - net_info_ratelimited("IrCOMM protocol (Dag Brattli)\n"); - - return 0; -} - -static void __exit ircomm_cleanup(void) -{ - hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close); - -#ifdef CONFIG_PROC_FS - remove_proc_entry("ircomm", proc_irda); -#endif /* CONFIG_PROC_FS */ -} - -/* - * Function ircomm_open (client_notify) - * - * Start a new IrCOMM instance - * - */ -struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line) -{ - struct ircomm_cb *self = NULL; - int ret; - - pr_debug("%s(), service_type=0x%02x\n", __func__ , - service_type); - - IRDA_ASSERT(ircomm != NULL, return NULL;); - - self = kzalloc(sizeof(struct ircomm_cb), GFP_KERNEL); - if (self == NULL) - return NULL; - - self->notify = *notify; - self->magic = IRCOMM_MAGIC; - - /* Check if we should use IrLMP or IrTTP */ - if (service_type & IRCOMM_3_WIRE_RAW) { - self->flow_status = FLOW_START; - ret = ircomm_open_lsap(self); - } else - ret = ircomm_open_tsap(self); - - if (ret < 0) { - kfree(self); - return NULL; - } - - self->service_type = service_type; - self->line = line; - - hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL); - - ircomm_next_state(self, IRCOMM_IDLE); - - return self; -} - -EXPORT_SYMBOL(ircomm_open); - -/* - * Function ircomm_close_instance (self) - * - * Remove IrCOMM instance - * - */ -static int __ircomm_close(struct ircomm_cb *self) -{ - /* Disconnect link if any */ - ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL); - - /* Remove TSAP */ - if (self->tsap) { - irttp_close_tsap(self->tsap); - self->tsap = NULL; - } - - /* Remove LSAP */ - if (self->lsap) { - irlmp_close_lsap(self->lsap); - self->lsap = NULL; - } - self->magic = 0; - - kfree(self); - - return 0; -} - -/* - * Function ircomm_close (self) - * - * Closes and removes the specified IrCOMM instance - * - */ -int ircomm_close(struct ircomm_cb *self) -{ - struct ircomm_cb *entry; - - IRDA_ASSERT(self != NULL, return -EIO;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;); - - entry = hashbin_remove(ircomm, self->line, NULL); - - IRDA_ASSERT(entry == self, return -1;); - - return __ircomm_close(self); -} - -EXPORT_SYMBOL(ircomm_close); - -/* - * Function ircomm_connect_request (self, service_type) - * - * Impl. of this function is differ from one of the reference. This - * function does discovery as well as sending connect request - * - */ -int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, - __u32 saddr, __u32 daddr, struct sk_buff *skb, - __u8 service_type) -{ - struct ircomm_info info; - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); - - self->service_type= service_type; - - info.dlsap_sel = dlsap_sel; - info.saddr = saddr; - info.daddr = daddr; - - ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info); - - return ret; -} - -EXPORT_SYMBOL(ircomm_connect_request); - -/* - * Function ircomm_connect_indication (self, qos, skb) - * - * Notify user layer about the incoming connection - * - */ -void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, - struct ircomm_info *info) -{ - /* - * If there are any data hiding in the control channel, we must - * deliver it first. The side effect is that the control channel - * will be removed from the skb - */ - if (self->notify.connect_indication) - self->notify.connect_indication(self->notify.instance, self, - info->qos, info->max_data_size, - info->max_header_size, skb); - else { - pr_debug("%s(), missing handler\n", __func__); - } -} - -/* - * Function ircomm_connect_response (self, userdata, max_sdu_size) - * - * User accepts connection - * - */ -int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) -{ - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); - - ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL); - - return ret; -} - -EXPORT_SYMBOL(ircomm_connect_response); - -/* - * Function connect_confirm (self, skb) - * - * Notify user layer that the link is now connected - * - */ -void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, - struct ircomm_info *info) -{ - if (self->notify.connect_confirm ) - self->notify.connect_confirm(self->notify.instance, - self, info->qos, - info->max_data_size, - info->max_header_size, skb); - else { - pr_debug("%s(), missing handler\n", __func__); - } -} - -/* - * Function ircomm_data_request (self, userdata) - * - * Send IrCOMM data to peer device - * - */ -int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb) -{ - int ret; - - IRDA_ASSERT(self != NULL, return -EFAULT;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); - IRDA_ASSERT(skb != NULL, return -EFAULT;); - - ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL); - - return ret; -} - -EXPORT_SYMBOL(ircomm_data_request); - -/* - * Function ircomm_data_indication (self, skb) - * - * Data arrived, so deliver it to user - * - */ -void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(skb->len > 0, return;); - - if (self->notify.data_indication) - self->notify.data_indication(self->notify.instance, self, skb); - else { - pr_debug("%s(), missing handler\n", __func__); - } -} - -/* - * Function ircomm_process_data (self, skb) - * - * Data arrived which may contain control channel data - * - */ -void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb) -{ - int clen; - - IRDA_ASSERT(skb->len > 0, return;); - - clen = skb->data[0]; - - /* - * Input validation check: a stir4200/mcp2150 combinations sometimes - * results in frames with clen > remaining packet size. These are - * illegal; if we throw away just this frame then it seems to carry on - * fine - */ - if (unlikely(skb->len < (clen + 1))) { - pr_debug("%s() throwing away illegal frame\n", - __func__); - return; - } - - /* - * If there are any data hiding in the control channel, we must - * deliver it first. The side effect is that the control channel - * will be removed from the skb - */ - if (clen > 0) - ircomm_control_indication(self, skb, clen); - - /* Remove control channel from data channel */ - skb_pull(skb, clen+1); - - if (skb->len) - ircomm_data_indication(self, skb); - else { - pr_debug("%s(), data was control info only!\n", - __func__); - } -} - -/* - * Function ircomm_control_request (self, params) - * - * Send control data to peer device - * - */ -int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb) -{ - int ret; - - IRDA_ASSERT(self != NULL, return -EFAULT;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); - IRDA_ASSERT(skb != NULL, return -EFAULT;); - - ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL); - - return ret; -} - -EXPORT_SYMBOL(ircomm_control_request); - -/* - * Function ircomm_control_indication (self, skb) - * - * Data has arrived on the control channel - * - */ -static void ircomm_control_indication(struct ircomm_cb *self, - struct sk_buff *skb, int clen) -{ - /* Use udata for delivering data on the control channel */ - if (self->notify.udata_indication) { - struct sk_buff *ctrl_skb; - - /* We don't own the skb, so clone it */ - ctrl_skb = skb_clone(skb, GFP_ATOMIC); - if (!ctrl_skb) - return; - - /* Remove data channel from control channel */ - skb_trim(ctrl_skb, clen+1); - - self->notify.udata_indication(self->notify.instance, self, - ctrl_skb); - - /* Drop reference count - - * see ircomm_tty_control_indication(). */ - dev_kfree_skb(ctrl_skb); - } else { - pr_debug("%s(), missing handler\n", __func__); - } -} - -/* - * Function ircomm_disconnect_request (self, userdata, priority) - * - * User layer wants to disconnect the IrCOMM connection - * - */ -int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata) -{ - struct ircomm_info info; - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); - - ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata, - &info); - return ret; -} - -EXPORT_SYMBOL(ircomm_disconnect_request); - -/* - * Function disconnect_indication (self, skb) - * - * Tell user that the link has been disconnected - * - */ -void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, - struct ircomm_info *info) -{ - IRDA_ASSERT(info != NULL, return;); - - if (self->notify.disconnect_indication) { - self->notify.disconnect_indication(self->notify.instance, self, - info->reason, skb); - } else { - pr_debug("%s(), missing handler\n", __func__); - } -} - -/* - * Function ircomm_flow_request (self, flow) - * - * - * - */ -void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - - if (self->service_type == IRCOMM_3_WIRE_RAW) - return; - - irttp_flow_request(self->tsap, flow); -} - -EXPORT_SYMBOL(ircomm_flow_request); - -#ifdef CONFIG_PROC_FS -static void *ircomm_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct ircomm_cb *self; - loff_t off = 0; - - spin_lock_irq(&ircomm->hb_spinlock); - - for (self = (struct ircomm_cb *) hashbin_get_first(ircomm); - self != NULL; - self = (struct ircomm_cb *) hashbin_get_next(ircomm)) { - if (off++ == *pos) - break; - - } - return self; -} - -static void *ircomm_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - - return (void *) hashbin_get_next(ircomm); -} - -static void ircomm_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_irq(&ircomm->hb_spinlock); -} - -static int ircomm_seq_show(struct seq_file *seq, void *v) -{ - const struct ircomm_cb *self = v; - - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EINVAL; ); - - if(self->line < 0x10) - seq_printf(seq, "ircomm%d", self->line); - else - seq_printf(seq, "irlpt%d", self->line - 0x10); - - seq_printf(seq, - " state: %s, slsap_sel: %#02x, dlsap_sel: %#02x, mode:", - ircomm_state[ self->state], - self->slsap_sel, self->dlsap_sel); - - if(self->service_type & IRCOMM_3_WIRE_RAW) - seq_printf(seq, " 3-wire-raw"); - if(self->service_type & IRCOMM_3_WIRE) - seq_printf(seq, " 3-wire"); - if(self->service_type & IRCOMM_9_WIRE) - seq_printf(seq, " 9-wire"); - if(self->service_type & IRCOMM_CENTRONICS) - seq_printf(seq, " Centronics"); - seq_putc(seq, '\n'); - - return 0; -} - -static const struct seq_operations ircomm_seq_ops = { - .start = ircomm_seq_start, - .next = ircomm_seq_next, - .stop = ircomm_seq_stop, - .show = ircomm_seq_show, -}; - -static int ircomm_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &ircomm_seq_ops); -} -#endif /* CONFIG_PROC_FS */ - -MODULE_AUTHOR("Dag Brattli <dag@brattli.net>"); -MODULE_DESCRIPTION("IrCOMM protocol"); -MODULE_LICENSE("GPL"); - -module_init(ircomm_init); -module_exit(ircomm_cleanup); diff --git a/drivers/staging/irda/net/ircomm/ircomm_event.c b/drivers/staging/irda/net/ircomm/ircomm_event.c deleted file mode 100644 index b0730ac9f388..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_event.c +++ /dev/null @@ -1,246 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_event.c - * Version: 1.0 - * Description: IrCOMM layer state machine - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Jun 6 20:33:11 1999 - * Modified at: Sun Dec 12 13:44:32 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/proc_fs.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irlmp.h> -#include <net/irda/iriap.h> -#include <net/irda/irttp.h> -#include <net/irda/irias_object.h> - -#include <net/irda/ircomm_core.h> -#include <net/irda/ircomm_event.h> - -static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info); -static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info); -static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info); -static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info); - -const char *const ircomm_state[] = { - "IRCOMM_IDLE", - "IRCOMM_WAITI", - "IRCOMM_WAITR", - "IRCOMM_CONN", -}; - -static const char *const ircomm_event[] __maybe_unused = { - "IRCOMM_CONNECT_REQUEST", - "IRCOMM_CONNECT_RESPONSE", - "IRCOMM_TTP_CONNECT_INDICATION", - "IRCOMM_LMP_CONNECT_INDICATION", - "IRCOMM_TTP_CONNECT_CONFIRM", - "IRCOMM_LMP_CONNECT_CONFIRM", - - "IRCOMM_LMP_DISCONNECT_INDICATION", - "IRCOMM_TTP_DISCONNECT_INDICATION", - "IRCOMM_DISCONNECT_REQUEST", - - "IRCOMM_TTP_DATA_INDICATION", - "IRCOMM_LMP_DATA_INDICATION", - "IRCOMM_DATA_REQUEST", - "IRCOMM_CONTROL_REQUEST", - "IRCOMM_CONTROL_INDICATION", -}; - -static int (*state[])(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info) = -{ - ircomm_state_idle, - ircomm_state_waiti, - ircomm_state_waitr, - ircomm_state_conn, -}; - -/* - * Function ircomm_state_idle (self, event, skb) - * - * IrCOMM is currently idle - * - */ -static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info) -{ - int ret = 0; - - switch (event) { - case IRCOMM_CONNECT_REQUEST: - ircomm_next_state(self, IRCOMM_WAITI); - ret = self->issue.connect_request(self, skb, info); - break; - case IRCOMM_TTP_CONNECT_INDICATION: - case IRCOMM_LMP_CONNECT_INDICATION: - ircomm_next_state(self, IRCOMM_WAITR); - ircomm_connect_indication(self, skb, info); - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_state_waiti (self, event, skb) - * - * The IrCOMM user has requested an IrCOMM connection to the remote - * device and is awaiting confirmation - */ -static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info) -{ - int ret = 0; - - switch (event) { - case IRCOMM_TTP_CONNECT_CONFIRM: - case IRCOMM_LMP_CONNECT_CONFIRM: - ircomm_next_state(self, IRCOMM_CONN); - ircomm_connect_confirm(self, skb, info); - break; - case IRCOMM_TTP_DISCONNECT_INDICATION: - case IRCOMM_LMP_DISCONNECT_INDICATION: - ircomm_next_state(self, IRCOMM_IDLE); - ircomm_disconnect_indication(self, skb, info); - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_state_waitr (self, event, skb) - * - * IrCOMM has received an incoming connection request and is awaiting - * response from the user - */ -static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info) -{ - int ret = 0; - - switch (event) { - case IRCOMM_CONNECT_RESPONSE: - ircomm_next_state(self, IRCOMM_CONN); - ret = self->issue.connect_response(self, skb); - break; - case IRCOMM_DISCONNECT_REQUEST: - ircomm_next_state(self, IRCOMM_IDLE); - ret = self->issue.disconnect_request(self, skb, info); - break; - case IRCOMM_TTP_DISCONNECT_INDICATION: - case IRCOMM_LMP_DISCONNECT_INDICATION: - ircomm_next_state(self, IRCOMM_IDLE); - ircomm_disconnect_indication(self, skb, info); - break; - default: - pr_debug("%s(), unknown event = %s\n", __func__ , - ircomm_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_state_conn (self, event, skb) - * - * IrCOMM is connected to the peer IrCOMM device - * - */ -static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info) -{ - int ret = 0; - - switch (event) { - case IRCOMM_DATA_REQUEST: - ret = self->issue.data_request(self, skb, 0); - break; - case IRCOMM_TTP_DATA_INDICATION: - ircomm_process_data(self, skb); - break; - case IRCOMM_LMP_DATA_INDICATION: - ircomm_data_indication(self, skb); - break; - case IRCOMM_CONTROL_REQUEST: - /* Just send a separate frame for now */ - ret = self->issue.data_request(self, skb, skb->len); - break; - case IRCOMM_TTP_DISCONNECT_INDICATION: - case IRCOMM_LMP_DISCONNECT_INDICATION: - ircomm_next_state(self, IRCOMM_IDLE); - ircomm_disconnect_indication(self, skb, info); - break; - case IRCOMM_DISCONNECT_REQUEST: - ircomm_next_state(self, IRCOMM_IDLE); - ret = self->issue.disconnect_request(self, skb, info); - break; - default: - pr_debug("%s(), unknown event = %s\n", __func__ , - ircomm_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_do_event (self, event, skb) - * - * Process event - * - */ -int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event, - struct sk_buff *skb, struct ircomm_info *info) -{ - pr_debug("%s: state=%s, event=%s\n", __func__ , - ircomm_state[self->state], ircomm_event[event]); - - return (*state[self->state])(self, event, skb, info); -} - -/* - * Function ircomm_next_state (self, state) - * - * Switch state - * - */ -void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state) -{ - self->state = state; - - pr_debug("%s: next state=%s, service type=%d\n", __func__ , - ircomm_state[self->state], self->service_type); -} diff --git a/drivers/staging/irda/net/ircomm/ircomm_lmp.c b/drivers/staging/irda/net/ircomm/ircomm_lmp.c deleted file mode 100644 index e4cc847bb933..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_lmp.c +++ /dev/null @@ -1,350 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_lmp.c - * Version: 1.0 - * Description: Interface between IrCOMM and IrLMP - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Jun 6 20:48:27 1999 - * Modified at: Sun Dec 12 13:44:17 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Sources: Previous IrLPT work by Thomas Davis - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/init.h> -#include <linux/gfp.h> - -#include <net/irda/irda.h> -#include <net/irda/irlmp.h> -#include <net/irda/iriap.h> -#include <net/irda/irda_device.h> /* struct irda_skb_cb */ - -#include <net/irda/ircomm_event.h> -#include <net/irda/ircomm_lmp.h> - - -/* - * Function ircomm_lmp_connect_request (self, userdata) - * - * - * - */ -static int ircomm_lmp_connect_request(struct ircomm_cb *self, - struct sk_buff *userdata, - struct ircomm_info *info) -{ - int ret = 0; - - /* Don't forget to refcount it - should be NULL anyway */ - if(userdata) - skb_get(userdata); - - ret = irlmp_connect_request(self->lsap, info->dlsap_sel, - info->saddr, info->daddr, NULL, userdata); - return ret; -} - -/* - * Function ircomm_lmp_connect_response (self, skb) - * - * - * - */ -static int ircomm_lmp_connect_response(struct ircomm_cb *self, - struct sk_buff *userdata) -{ - struct sk_buff *tx_skb; - - /* Any userdata supplied? */ - if (userdata == NULL) { - tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); - if (!tx_skb) - return -ENOMEM; - - /* Reserve space for MUX and LAP header */ - skb_reserve(tx_skb, LMP_MAX_HEADER); - } else { - /* - * Check that the client has reserved enough space for - * headers - */ - IRDA_ASSERT(skb_headroom(userdata) >= LMP_MAX_HEADER, - return -1;); - - /* Don't forget to refcount it - should be NULL anyway */ - skb_get(userdata); - tx_skb = userdata; - } - - return irlmp_connect_response(self->lsap, tx_skb); -} - -static int ircomm_lmp_disconnect_request(struct ircomm_cb *self, - struct sk_buff *userdata, - struct ircomm_info *info) -{ - struct sk_buff *tx_skb; - int ret; - - if (!userdata) { - tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); - if (!tx_skb) - return -ENOMEM; - - /* Reserve space for MUX and LAP header */ - skb_reserve(tx_skb, LMP_MAX_HEADER); - userdata = tx_skb; - } else { - /* Don't forget to refcount it - should be NULL anyway */ - skb_get(userdata); - } - - ret = irlmp_disconnect_request(self->lsap, userdata); - - return ret; -} - -/* - * Function ircomm_lmp_flow_control (skb) - * - * This function is called when a data frame we have sent to IrLAP has - * been deallocated. We do this to make sure we don't flood IrLAP with - * frames, since we are not using the IrTTP flow control mechanism - */ -static void ircomm_lmp_flow_control(struct sk_buff *skb) -{ - struct irda_skb_cb *cb; - struct ircomm_cb *self; - int line; - - IRDA_ASSERT(skb != NULL, return;); - - cb = (struct irda_skb_cb *) skb->cb; - - line = cb->line; - - self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL); - if (!self) { - pr_debug("%s(), didn't find myself\n", __func__); - return; - } - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - - self->pkt_count--; - - if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) { - pr_debug("%s(), asking TTY to start again!\n", __func__); - self->flow_status = FLOW_START; - if (self->notify.flow_indication) - self->notify.flow_indication(self->notify.instance, - self, FLOW_START); - } -} - -/* - * Function ircomm_lmp_data_request (self, userdata) - * - * Send data frame to peer device - * - */ -static int ircomm_lmp_data_request(struct ircomm_cb *self, - struct sk_buff *skb, - int not_used) -{ - struct irda_skb_cb *cb; - int ret; - - IRDA_ASSERT(skb != NULL, return -1;); - - cb = (struct irda_skb_cb *) skb->cb; - - cb->line = self->line; - - pr_debug("%s(), sending frame\n", __func__); - - /* Don't forget to refcount it - see ircomm_tty_do_softint() */ - skb_get(skb); - - skb_orphan(skb); - skb->destructor = ircomm_lmp_flow_control; - - if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) { - pr_debug("%s(), asking TTY to slow down!\n", __func__); - self->flow_status = FLOW_STOP; - if (self->notify.flow_indication) - self->notify.flow_indication(self->notify.instance, - self, FLOW_STOP); - } - ret = irlmp_data_request(self->lsap, skb); - if (ret) { - net_err_ratelimited("%s(), failed\n", __func__); - /* irlmp_data_request already free the packet */ - } - - return ret; -} - -/* - * Function ircomm_lmp_data_indication (instance, sap, skb) - * - * Incoming data which we must deliver to the state machine, to check - * we are still connected. - */ -static int ircomm_lmp_data_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - ircomm_do_event(self, IRCOMM_LMP_DATA_INDICATION, skb, NULL); - - /* Drop reference count - see ircomm_tty_data_indication(). */ - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function ircomm_lmp_connect_confirm (instance, sap, qos, max_sdu_size, - * max_header_size, skb) - * - * Connection has been confirmed by peer device - * - */ -static void ircomm_lmp_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_seg_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *) instance; - struct ircomm_info info; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(qos != NULL, return;); - - info.max_data_size = max_seg_size; - info.max_header_size = max_header_size; - info.qos = qos; - - ircomm_do_event(self, IRCOMM_LMP_CONNECT_CONFIRM, skb, &info); - - /* Drop reference count - see ircomm_tty_connect_confirm(). */ - dev_kfree_skb(skb); -} - -/* - * Function ircomm_lmp_connect_indication (instance, sap, qos, max_sdu_size, - * max_header_size, skb) - * - * Peer device wants to make a connection with us - * - */ -static void ircomm_lmp_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_seg_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *)instance; - struct ircomm_info info; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(qos != NULL, return;); - - info.max_data_size = max_seg_size; - info.max_header_size = max_header_size; - info.qos = qos; - - ircomm_do_event(self, IRCOMM_LMP_CONNECT_INDICATION, skb, &info); - - /* Drop reference count - see ircomm_tty_connect_indication(). */ - dev_kfree_skb(skb); -} - -/* - * Function ircomm_lmp_disconnect_indication (instance, sap, reason, skb) - * - * Peer device has closed the connection, or the link went down for some - * other reason - */ -static void ircomm_lmp_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *) instance; - struct ircomm_info info; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - - info.reason = reason; - - ircomm_do_event(self, IRCOMM_LMP_DISCONNECT_INDICATION, skb, &info); - - /* Drop reference count - see ircomm_tty_disconnect_indication(). */ - if(skb) - dev_kfree_skb(skb); -} -/* - * Function ircomm_open_lsap (self) - * - * Open LSAP. This function will only be used when using "raw" services - * - */ -int ircomm_open_lsap(struct ircomm_cb *self) -{ - notify_t notify; - - /* Register callbacks */ - irda_notify_init(¬ify); - notify.data_indication = ircomm_lmp_data_indication; - notify.connect_confirm = ircomm_lmp_connect_confirm; - notify.connect_indication = ircomm_lmp_connect_indication; - notify.disconnect_indication = ircomm_lmp_disconnect_indication; - notify.instance = self; - strlcpy(notify.name, "IrCOMM", sizeof(notify.name)); - - self->lsap = irlmp_open_lsap(LSAP_ANY, ¬ify, 0); - if (!self->lsap) { - pr_debug("%sfailed to allocate tsap\n", __func__); - return -1; - } - self->slsap_sel = self->lsap->slsap_sel; - - /* - * Initialize the call-table for issuing commands - */ - self->issue.data_request = ircomm_lmp_data_request; - self->issue.connect_request = ircomm_lmp_connect_request; - self->issue.connect_response = ircomm_lmp_connect_response; - self->issue.disconnect_request = ircomm_lmp_disconnect_request; - - return 0; -} diff --git a/drivers/staging/irda/net/ircomm/ircomm_param.c b/drivers/staging/irda/net/ircomm/ircomm_param.c deleted file mode 100644 index 5728e76ca6d5..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_param.c +++ /dev/null @@ -1,501 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_param.c - * Version: 1.0 - * Description: Parameter handling for the IrCOMM protocol - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Jun 7 10:25:11 1999 - * Modified at: Sun Jan 30 14:32:03 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/gfp.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> - -#include <net/irda/irda.h> -#include <net/irda/parameters.h> - -#include <net/irda/ircomm_core.h> -#include <net/irda/ircomm_tty_attach.h> -#include <net/irda/ircomm_tty.h> - -#include <net/irda/ircomm_param.h> - -static int ircomm_param_service_type(void *instance, irda_param_t *param, - int get); -static int ircomm_param_port_type(void *instance, irda_param_t *param, - int get); -static int ircomm_param_port_name(void *instance, irda_param_t *param, - int get); -static int ircomm_param_service_type(void *instance, irda_param_t *param, - int get); -static int ircomm_param_data_rate(void *instance, irda_param_t *param, - int get); -static int ircomm_param_data_format(void *instance, irda_param_t *param, - int get); -static int ircomm_param_flow_control(void *instance, irda_param_t *param, - int get); -static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get); -static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get); -static int ircomm_param_line_status(void *instance, irda_param_t *param, - int get); -static int ircomm_param_dte(void *instance, irda_param_t *param, int get); -static int ircomm_param_dce(void *instance, irda_param_t *param, int get); -static int ircomm_param_poll(void *instance, irda_param_t *param, int get); - -static const pi_minor_info_t pi_minor_call_table_common[] = { - { ircomm_param_service_type, PV_INT_8_BITS }, - { ircomm_param_port_type, PV_INT_8_BITS }, - { ircomm_param_port_name, PV_STRING } -}; -static const pi_minor_info_t pi_minor_call_table_non_raw[] = { - { ircomm_param_data_rate, PV_INT_32_BITS | PV_BIG_ENDIAN }, - { ircomm_param_data_format, PV_INT_8_BITS }, - { ircomm_param_flow_control, PV_INT_8_BITS }, - { ircomm_param_xon_xoff, PV_INT_16_BITS }, - { ircomm_param_enq_ack, PV_INT_16_BITS }, - { ircomm_param_line_status, PV_INT_8_BITS } -}; -static const pi_minor_info_t pi_minor_call_table_9_wire[] = { - { ircomm_param_dte, PV_INT_8_BITS }, - { ircomm_param_dce, PV_INT_8_BITS }, - { ircomm_param_poll, PV_NO_VALUE }, -}; - -static const pi_major_info_t pi_major_call_table[] = { - { pi_minor_call_table_common, 3 }, - { pi_minor_call_table_non_raw, 6 }, - { pi_minor_call_table_9_wire, 3 } -/* { pi_minor_call_table_centronics } */ -}; - -pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 }; - -/* - * Function ircomm_param_request (self, pi, flush) - * - * Queue a parameter for the control channel - * - */ -int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) -{ - unsigned long flags; - struct sk_buff *skb; - int count; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - /* Make sure we don't send parameters for raw mode */ - if (self->service_type == IRCOMM_3_WIRE_RAW) - return 0; - - spin_lock_irqsave(&self->spinlock, flags); - - skb = self->ctrl_skb; - if (!skb) { - skb = alloc_skb(256, GFP_ATOMIC); - if (!skb) { - spin_unlock_irqrestore(&self->spinlock, flags); - return -ENOMEM; - } - - skb_reserve(skb, self->max_header_size); - self->ctrl_skb = skb; - } - /* - * Inserting is a little bit tricky since we don't know how much - * room we will need. But this should hopefully work OK - */ - count = irda_param_insert(self, pi, skb_tail_pointer(skb), - skb_tailroom(skb), &ircomm_param_info); - if (count < 0) { - net_warn_ratelimited("%s(), no room for parameter!\n", - __func__); - spin_unlock_irqrestore(&self->spinlock, flags); - return -1; - } - skb_put(skb, count); - pr_debug("%s(), skb->len=%d\n", __func__, skb->len); - - spin_unlock_irqrestore(&self->spinlock, flags); - - if (flush) { - /* ircomm_tty_do_softint will take care of the rest */ - schedule_work(&self->tqueue); - } - - return count; -} - -/* - * Function ircomm_param_service_type (self, buf, len) - * - * Handle service type, this function will both be called after the LM-IAS - * query and then the remote device sends its initial parameters - * - */ -static int ircomm_param_service_type(void *instance, irda_param_t *param, - int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - __u8 service_type = (__u8) param->pv.i; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) { - param->pv.i = self->settings.service_type; - return 0; - } - - /* Find all common service types */ - service_type &= self->service_type; - if (!service_type) { - pr_debug("%s(), No common service type to use!\n", __func__); - return -1; - } - pr_debug("%s(), services in common=%02x\n", __func__ , - service_type); - - /* - * Now choose a preferred service type of those available - */ - if (service_type & IRCOMM_CENTRONICS) - self->settings.service_type = IRCOMM_CENTRONICS; - else if (service_type & IRCOMM_9_WIRE) - self->settings.service_type = IRCOMM_9_WIRE; - else if (service_type & IRCOMM_3_WIRE) - self->settings.service_type = IRCOMM_3_WIRE; - else if (service_type & IRCOMM_3_WIRE_RAW) - self->settings.service_type = IRCOMM_3_WIRE_RAW; - - pr_debug("%s(), resulting service type=0x%02x\n", __func__ , - self->settings.service_type); - - /* - * Now the line is ready for some communication. Check if we are a - * server, and send over some initial parameters. - * Client do it in ircomm_tty_state_setup(). - * Note : we may get called from ircomm_tty_getvalue_confirm(), - * therefore before we even have open any socket. And self->client - * is initialised to TRUE only later. So, we check if the link is - * really initialised. - Jean II - */ - if ((self->max_header_size != IRCOMM_TTY_HDR_UNINITIALISED) && - (!self->client) && - (self->settings.service_type != IRCOMM_3_WIRE_RAW)) - { - /* Init connection */ - ircomm_tty_send_initial_parameters(self); - ircomm_tty_link_established(self); - } - - return 0; -} - -/* - * Function ircomm_param_port_type (self, param) - * - * The port type parameter tells if the devices are serial or parallel. - * Since we only advertise serial service, this parameter should only - * be equal to IRCOMM_SERIAL. - */ -static int ircomm_param_port_type(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) - param->pv.i = IRCOMM_SERIAL; - else { - self->settings.port_type = (__u8) param->pv.i; - - pr_debug("%s(), port type=%d\n", __func__ , - self->settings.port_type); - } - return 0; -} - -/* - * Function ircomm_param_port_name (self, param) - * - * Exchange port name - * - */ -static int ircomm_param_port_name(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) { - pr_debug("%s(), not imp!\n", __func__); - } else { - pr_debug("%s(), port-name=%s\n", __func__ , param->pv.c); - strncpy(self->settings.port_name, param->pv.c, 32); - } - - return 0; -} - -/* - * Function ircomm_param_data_rate (self, param) - * - * Exchange data rate to be used in this settings - * - */ -static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) - param->pv.i = self->settings.data_rate; - else - self->settings.data_rate = param->pv.i; - - pr_debug("%s(), data rate = %d\n", __func__ , param->pv.i); - - return 0; -} - -/* - * Function ircomm_param_data_format (self, param) - * - * Exchange data format to be used in this settings - * - */ -static int ircomm_param_data_format(void *instance, irda_param_t *param, - int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) - param->pv.i = self->settings.data_format; - else - self->settings.data_format = (__u8) param->pv.i; - - return 0; -} - -/* - * Function ircomm_param_flow_control (self, param) - * - * Exchange flow control settings to be used in this settings - * - */ -static int ircomm_param_flow_control(void *instance, irda_param_t *param, - int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) - param->pv.i = self->settings.flow_control; - else - self->settings.flow_control = (__u8) param->pv.i; - - pr_debug("%s(), flow control = 0x%02x\n", __func__ , (__u8)param->pv.i); - - return 0; -} - -/* - * Function ircomm_param_xon_xoff (self, param) - * - * Exchange XON/XOFF characters - * - */ -static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) { - param->pv.i = self->settings.xonxoff[0]; - param->pv.i |= self->settings.xonxoff[1] << 8; - } else { - self->settings.xonxoff[0] = (__u16) param->pv.i & 0xff; - self->settings.xonxoff[1] = (__u16) param->pv.i >> 8; - } - - pr_debug("%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ , - param->pv.i & 0xff, param->pv.i >> 8); - - return 0; -} - -/* - * Function ircomm_param_enq_ack (self, param) - * - * Exchange ENQ/ACK characters - * - */ -static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) { - param->pv.i = self->settings.enqack[0]; - param->pv.i |= self->settings.enqack[1] << 8; - } else { - self->settings.enqack[0] = (__u16) param->pv.i & 0xff; - self->settings.enqack[1] = (__u16) param->pv.i >> 8; - } - - pr_debug("%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ , - param->pv.i & 0xff, param->pv.i >> 8); - - return 0; -} - -/* - * Function ircomm_param_line_status (self, param) - * - * - * - */ -static int ircomm_param_line_status(void *instance, irda_param_t *param, - int get) -{ - pr_debug("%s(), not impl.\n", __func__); - - return 0; -} - -/* - * Function ircomm_param_dte (instance, param) - * - * If we get here, there must be some sort of null-modem connection, and - * we are probably working in server mode as well. - */ -static int ircomm_param_dte(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - __u8 dte; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (get) - param->pv.i = self->settings.dte; - else { - dte = (__u8) param->pv.i; - - self->settings.dce = 0; - - if (dte & IRCOMM_DELTA_DTR) - self->settings.dce |= (IRCOMM_DELTA_DSR| - IRCOMM_DELTA_RI | - IRCOMM_DELTA_CD); - if (dte & IRCOMM_DTR) - self->settings.dce |= (IRCOMM_DSR| - IRCOMM_RI | - IRCOMM_CD); - - if (dte & IRCOMM_DELTA_RTS) - self->settings.dce |= IRCOMM_DELTA_CTS; - if (dte & IRCOMM_RTS) - self->settings.dce |= IRCOMM_CTS; - - /* Take appropriate actions */ - ircomm_tty_check_modem_status(self); - - /* Null modem cable emulator */ - self->settings.null_modem = TRUE; - } - - return 0; -} - -/* - * Function ircomm_param_dce (instance, param) - * - * - * - */ -static int ircomm_param_dce(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - __u8 dce; - - pr_debug("%s(), dce = 0x%02x\n", __func__ , (__u8)param->pv.i); - - dce = (__u8) param->pv.i; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - self->settings.dce = dce; - - /* Check if any of the settings have changed */ - if (dce & 0x0f) { - if (dce & IRCOMM_DELTA_CTS) { - pr_debug("%s(), CTS\n", __func__); - } - } - - ircomm_tty_check_modem_status(self); - - return 0; -} - -/* - * Function ircomm_param_poll (instance, param) - * - * Called when the peer device is polling for the line settings - * - */ -static int ircomm_param_poll(void *instance, irda_param_t *param, int get) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - /* Poll parameters are always of length 0 (just a signal) */ - if (!get) { - /* Respond with DTE line settings */ - ircomm_param_request(self, IRCOMM_DTE, TRUE); - } - return 0; -} - - - - - diff --git a/drivers/staging/irda/net/ircomm/ircomm_ttp.c b/drivers/staging/irda/net/ircomm/ircomm_ttp.c deleted file mode 100644 index 4b81e0934770..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_ttp.c +++ /dev/null @@ -1,350 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_ttp.c - * Version: 1.0 - * Description: Interface between IrCOMM and IrTTP - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Jun 6 20:48:27 1999 - * Modified at: Mon Dec 13 11:35:13 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irlmp.h> -#include <net/irda/iriap.h> -#include <net/irda/irttp.h> - -#include <net/irda/ircomm_event.h> -#include <net/irda/ircomm_ttp.h> - -static int ircomm_ttp_data_indication(void *instance, void *sap, - struct sk_buff *skb); -static void ircomm_ttp_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb); -static void ircomm_ttp_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb); -static void ircomm_ttp_flow_indication(void *instance, void *sap, - LOCAL_FLOW cmd); -static void ircomm_ttp_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *skb); -static int ircomm_ttp_data_request(struct ircomm_cb *self, - struct sk_buff *skb, - int clen); -static int ircomm_ttp_connect_request(struct ircomm_cb *self, - struct sk_buff *userdata, - struct ircomm_info *info); -static int ircomm_ttp_connect_response(struct ircomm_cb *self, - struct sk_buff *userdata); -static int ircomm_ttp_disconnect_request(struct ircomm_cb *self, - struct sk_buff *userdata, - struct ircomm_info *info); - -/* - * Function ircomm_open_tsap (self) - * - * - * - */ -int ircomm_open_tsap(struct ircomm_cb *self) -{ - notify_t notify; - - /* Register callbacks */ - irda_notify_init(¬ify); - notify.data_indication = ircomm_ttp_data_indication; - notify.connect_confirm = ircomm_ttp_connect_confirm; - notify.connect_indication = ircomm_ttp_connect_indication; - notify.flow_indication = ircomm_ttp_flow_indication; - notify.disconnect_indication = ircomm_ttp_disconnect_indication; - notify.instance = self; - strlcpy(notify.name, "IrCOMM", sizeof(notify.name)); - - self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, - ¬ify); - if (!self->tsap) { - pr_debug("%sfailed to allocate tsap\n", __func__); - return -1; - } - self->slsap_sel = self->tsap->stsap_sel; - - /* - * Initialize the call-table for issuing commands - */ - self->issue.data_request = ircomm_ttp_data_request; - self->issue.connect_request = ircomm_ttp_connect_request; - self->issue.connect_response = ircomm_ttp_connect_response; - self->issue.disconnect_request = ircomm_ttp_disconnect_request; - - return 0; -} - -/* - * Function ircomm_ttp_connect_request (self, userdata) - * - * - * - */ -static int ircomm_ttp_connect_request(struct ircomm_cb *self, - struct sk_buff *userdata, - struct ircomm_info *info) -{ - int ret = 0; - - /* Don't forget to refcount it - should be NULL anyway */ - if(userdata) - skb_get(userdata); - - ret = irttp_connect_request(self->tsap, info->dlsap_sel, - info->saddr, info->daddr, NULL, - TTP_SAR_DISABLE, userdata); - - return ret; -} - -/* - * Function ircomm_ttp_connect_response (self, skb) - * - * - * - */ -static int ircomm_ttp_connect_response(struct ircomm_cb *self, - struct sk_buff *userdata) -{ - int ret; - - /* Don't forget to refcount it - should be NULL anyway */ - if(userdata) - skb_get(userdata); - - ret = irttp_connect_response(self->tsap, TTP_SAR_DISABLE, userdata); - - return ret; -} - -/* - * Function ircomm_ttp_data_request (self, userdata) - * - * Send IrCOMM data to IrTTP layer. Currently we do not try to combine - * control data with pure data, so they will be sent as separate frames. - * Should not be a big problem though, since control frames are rare. But - * some of them are sent after connection establishment, so this can - * increase the latency a bit. - */ -static int ircomm_ttp_data_request(struct ircomm_cb *self, - struct sk_buff *skb, - int clen) -{ - int ret; - - IRDA_ASSERT(skb != NULL, return -1;); - - pr_debug("%s(), clen=%d\n", __func__ , clen); - - /* - * Insert clen field, currently we either send data only, or control - * only frames, to make things easier and avoid queueing - */ - IRDA_ASSERT(skb_headroom(skb) >= IRCOMM_HEADER_SIZE, return -1;); - - /* Don't forget to refcount it - see ircomm_tty_do_softint() */ - skb_get(skb); - - skb_push(skb, IRCOMM_HEADER_SIZE); - - skb->data[0] = clen; - - ret = irttp_data_request(self->tsap, skb); - if (ret) { - net_err_ratelimited("%s(), failed\n", __func__); - /* irttp_data_request already free the packet */ - } - - return ret; -} - -/* - * Function ircomm_ttp_data_indication (instance, sap, skb) - * - * Incoming data - * - */ -static int ircomm_ttp_data_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - ircomm_do_event(self, IRCOMM_TTP_DATA_INDICATION, skb, NULL); - - /* Drop reference count - see ircomm_tty_data_indication(). */ - dev_kfree_skb(skb); - - return 0; -} - -static void ircomm_ttp_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *) instance; - struct ircomm_info info; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(qos != NULL, goto out;); - - if (max_sdu_size != TTP_SAR_DISABLE) { - net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n", - __func__); - goto out; - } - - info.max_data_size = irttp_get_max_seg_size(self->tsap) - - IRCOMM_HEADER_SIZE; - info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE; - info.qos = qos; - - ircomm_do_event(self, IRCOMM_TTP_CONNECT_CONFIRM, skb, &info); - -out: - /* Drop reference count - see ircomm_tty_connect_confirm(). */ - dev_kfree_skb(skb); -} - -/* - * Function ircomm_ttp_connect_indication (instance, sap, qos, max_sdu_size, - * max_header_size, skb) - * - * - * - */ -static void ircomm_ttp_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *)instance; - struct ircomm_info info; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(qos != NULL, goto out;); - - if (max_sdu_size != TTP_SAR_DISABLE) { - net_err_ratelimited("%s(), SAR not allowed for IrCOMM!\n", - __func__); - goto out; - } - - info.max_data_size = irttp_get_max_seg_size(self->tsap) - - IRCOMM_HEADER_SIZE; - info.max_header_size = max_header_size + IRCOMM_HEADER_SIZE; - info.qos = qos; - - ircomm_do_event(self, IRCOMM_TTP_CONNECT_INDICATION, skb, &info); - -out: - /* Drop reference count - see ircomm_tty_connect_indication(). */ - dev_kfree_skb(skb); -} - -/* - * Function ircomm_ttp_disconnect_request (self, userdata, info) - * - * - * - */ -static int ircomm_ttp_disconnect_request(struct ircomm_cb *self, - struct sk_buff *userdata, - struct ircomm_info *info) -{ - int ret; - - /* Don't forget to refcount it - should be NULL anyway */ - if(userdata) - skb_get(userdata); - - ret = irttp_disconnect_request(self->tsap, userdata, P_NORMAL); - - return ret; -} - -/* - * Function ircomm_ttp_disconnect_indication (instance, sap, reason, skb) - * - * - * - */ -static void ircomm_ttp_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *skb) -{ - struct ircomm_cb *self = (struct ircomm_cb *) instance; - struct ircomm_info info; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - - info.reason = reason; - - ircomm_do_event(self, IRCOMM_TTP_DISCONNECT_INDICATION, skb, &info); - - /* Drop reference count - see ircomm_tty_disconnect_indication(). */ - if(skb) - dev_kfree_skb(skb); -} - -/* - * Function ircomm_ttp_flow_indication (instance, sap, cmd) - * - * Layer below is telling us to start or stop the flow of data - * - */ -static void ircomm_ttp_flow_indication(void *instance, void *sap, - LOCAL_FLOW cmd) -{ - struct ircomm_cb *self = (struct ircomm_cb *) instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); - - if (self->notify.flow_indication) - self->notify.flow_indication(self->notify.instance, self, cmd); -} - - diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty.c b/drivers/staging/irda/net/ircomm/ircomm_tty.c deleted file mode 100644 index 473abfaffe7b..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_tty.c +++ /dev/null @@ -1,1329 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_tty.c - * Version: 1.0 - * Description: IrCOMM serial TTY driver - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Jun 6 21:00:56 1999 - * Modified at: Wed Feb 23 00:09:02 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Sources: serial.c and previous IrCOMM work by Takahide Higuchi - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/sched/signal.h> -#include <linux/seq_file.h> -#include <linux/termios.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/interrupt.h> -#include <linux/device.h> /* for MODULE_ALIAS_CHARDEV_MAJOR */ - -#include <linux/uaccess.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> - -#include <net/irda/ircomm_core.h> -#include <net/irda/ircomm_param.h> -#include <net/irda/ircomm_tty_attach.h> -#include <net/irda/ircomm_tty.h> - -static int ircomm_tty_install(struct tty_driver *driver, - struct tty_struct *tty); -static int ircomm_tty_open(struct tty_struct *tty, struct file *filp); -static void ircomm_tty_close(struct tty_struct * tty, struct file *filp); -static int ircomm_tty_write(struct tty_struct * tty, - const unsigned char *buf, int count); -static int ircomm_tty_write_room(struct tty_struct *tty); -static void ircomm_tty_throttle(struct tty_struct *tty); -static void ircomm_tty_unthrottle(struct tty_struct *tty); -static int ircomm_tty_chars_in_buffer(struct tty_struct *tty); -static void ircomm_tty_flush_buffer(struct tty_struct *tty); -static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch); -static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout); -static void ircomm_tty_hangup(struct tty_struct *tty); -static void ircomm_tty_do_softint(struct work_struct *work); -static void ircomm_tty_shutdown(struct ircomm_tty_cb *self); -static void ircomm_tty_stop(struct tty_struct *tty); - -static int ircomm_tty_data_indication(void *instance, void *sap, - struct sk_buff *skb); -static int ircomm_tty_control_indication(void *instance, void *sap, - struct sk_buff *skb); -static void ircomm_tty_flow_indication(void *instance, void *sap, - LOCAL_FLOW cmd); -#ifdef CONFIG_PROC_FS -static const struct file_operations ircomm_tty_proc_fops; -#endif /* CONFIG_PROC_FS */ -static struct tty_driver *driver; - -static hashbin_t *ircomm_tty = NULL; - -static const struct tty_operations ops = { - .install = ircomm_tty_install, - .open = ircomm_tty_open, - .close = ircomm_tty_close, - .write = ircomm_tty_write, - .write_room = ircomm_tty_write_room, - .chars_in_buffer = ircomm_tty_chars_in_buffer, - .flush_buffer = ircomm_tty_flush_buffer, - .ioctl = ircomm_tty_ioctl, /* ircomm_tty_ioctl.c */ - .tiocmget = ircomm_tty_tiocmget, /* ircomm_tty_ioctl.c */ - .tiocmset = ircomm_tty_tiocmset, /* ircomm_tty_ioctl.c */ - .throttle = ircomm_tty_throttle, - .unthrottle = ircomm_tty_unthrottle, - .send_xchar = ircomm_tty_send_xchar, - .set_termios = ircomm_tty_set_termios, - .stop = ircomm_tty_stop, - .start = ircomm_tty_start, - .hangup = ircomm_tty_hangup, - .wait_until_sent = ircomm_tty_wait_until_sent, -#ifdef CONFIG_PROC_FS - .proc_fops = &ircomm_tty_proc_fops, -#endif /* CONFIG_PROC_FS */ -}; - -static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise) -{ - struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb, - port); - /* - * Here, we use to lock those two guys, but as ircomm_param_request() - * does it itself, I don't see the point (and I see the deadlock). - * Jean II - */ - if (raise) - self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR; - else - self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR); - - ircomm_param_request(self, IRCOMM_DTE, TRUE); -} - -static int ircomm_port_carrier_raised(struct tty_port *port) -{ - struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb, - port); - return self->settings.dce & IRCOMM_CD; -} - -static const struct tty_port_operations ircomm_port_ops = { - .dtr_rts = ircomm_port_raise_dtr_rts, - .carrier_raised = ircomm_port_carrier_raised, -}; - -/* - * Function ircomm_tty_init() - * - * Init IrCOMM TTY layer/driver - * - */ -static int __init ircomm_tty_init(void) -{ - driver = alloc_tty_driver(IRCOMM_TTY_PORTS); - if (!driver) - return -ENOMEM; - ircomm_tty = hashbin_new(HB_LOCK); - if (ircomm_tty == NULL) { - net_err_ratelimited("%s(), can't allocate hashbin!\n", - __func__); - put_tty_driver(driver); - return -ENOMEM; - } - - driver->driver_name = "ircomm"; - driver->name = "ircomm"; - driver->major = IRCOMM_TTY_MAJOR; - driver->minor_start = IRCOMM_TTY_MINOR; - driver->type = TTY_DRIVER_TYPE_SERIAL; - driver->subtype = SERIAL_TYPE_NORMAL; - driver->init_termios = tty_std_termios; - driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(driver, &ops); - if (tty_register_driver(driver)) { - net_err_ratelimited("%s(): Couldn't register serial driver\n", - __func__); - put_tty_driver(driver); - return -1; - } - return 0; -} - -static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - ircomm_tty_shutdown(self); - - self->magic = 0; - tty_port_destroy(&self->port); - kfree(self); -} - -/* - * Function ircomm_tty_cleanup () - * - * Remove IrCOMM TTY layer/driver - * - */ -static void __exit ircomm_tty_cleanup(void) -{ - int ret; - - ret = tty_unregister_driver(driver); - if (ret) { - net_err_ratelimited("%s(), failed to unregister driver\n", - __func__); - return; - } - - hashbin_delete(ircomm_tty, (FREE_FUNC) __ircomm_tty_cleanup); - put_tty_driver(driver); -} - -/* - * Function ircomm_startup (self) - * - * - * - */ -static int ircomm_tty_startup(struct ircomm_tty_cb *self) -{ - notify_t notify; - int ret = -ENODEV; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - /* Check if already open */ - if (tty_port_initialized(&self->port)) { - pr_debug("%s(), already open so break out!\n", __func__); - return 0; - } - tty_port_set_initialized(&self->port, 1); - - /* Register with IrCOMM */ - irda_notify_init(¬ify); - /* These callbacks we must handle ourselves */ - notify.data_indication = ircomm_tty_data_indication; - notify.udata_indication = ircomm_tty_control_indication; - notify.flow_indication = ircomm_tty_flow_indication; - - /* Use the ircomm_tty interface for these ones */ - notify.disconnect_indication = ircomm_tty_disconnect_indication; - notify.connect_confirm = ircomm_tty_connect_confirm; - notify.connect_indication = ircomm_tty_connect_indication; - strlcpy(notify.name, "ircomm_tty", sizeof(notify.name)); - notify.instance = self; - - if (!self->ircomm) { - self->ircomm = ircomm_open(¬ify, self->service_type, - self->line); - } - if (!self->ircomm) - goto err; - - self->slsap_sel = self->ircomm->slsap_sel; - - /* Connect IrCOMM link with remote device */ - ret = ircomm_tty_attach_cable(self); - if (ret < 0) { - net_err_ratelimited("%s(), error attaching cable!\n", __func__); - goto err; - } - - return 0; -err: - tty_port_set_initialized(&self->port, 0); - return ret; -} - -/* - * Function ircomm_block_til_ready (self, filp) - * - * - * - */ -static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, - struct tty_struct *tty, struct file *filp) -{ - struct tty_port *port = &self->port; - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - unsigned long flags; - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if (tty_io_error(tty)) { - tty_port_set_active(port, 1); - return 0; - } - - if (filp->f_flags & O_NONBLOCK) { - /* nonblock mode is set */ - if (C_BAUD(tty)) - tty_port_raise_dtr_rts(port); - tty_port_set_active(port, 1); - pr_debug("%s(), O_NONBLOCK requested!\n", __func__); - return 0; - } - - if (C_CLOCAL(tty)) { - pr_debug("%s(), doing CLOCAL!\n", __func__); - do_clocal = 1; - } - - /* Wait for carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, port->count is dropped by one, so that - * mgsl_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - - retval = 0; - add_wait_queue(&port->open_wait, &wait); - - pr_debug("%s(%d):block_til_ready before block on %s open_count=%d\n", - __FILE__, __LINE__, tty->driver->name, port->count); - - spin_lock_irqsave(&port->lock, flags); - port->count--; - port->blocked_open++; - spin_unlock_irqrestore(&port->lock, flags); - - while (1) { - if (C_BAUD(tty) && tty_port_initialized(port)) - tty_port_raise_dtr_rts(port); - - set_current_state(TASK_INTERRUPTIBLE); - - if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { - retval = (port->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS; - break; - } - - /* - * Check if link is ready now. Even if CLOCAL is - * specified, we cannot return before the IrCOMM link is - * ready - */ - if ((do_clocal || tty_port_carrier_raised(port)) && - self->state == IRCOMM_TTY_READY) - { - break; - } - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - pr_debug("%s(%d):block_til_ready blocking on %s open_count=%d\n", - __FILE__, __LINE__, tty->driver->name, port->count); - - schedule(); - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&port->open_wait, &wait); - - spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - spin_unlock_irqrestore(&port->lock, flags); - - pr_debug("%s(%d):block_til_ready after blocking on %s open_count=%d\n", - __FILE__, __LINE__, tty->driver->name, port->count); - - if (!retval) - tty_port_set_active(port, 1); - - return retval; -} - - -static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - struct ircomm_tty_cb *self; - unsigned int line = tty->index; - - /* Check if instance already exists */ - self = hashbin_lock_find(ircomm_tty, line, NULL); - if (!self) { - /* No, so make new instance */ - self = kzalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL); - if (self == NULL) - return -ENOMEM; - - tty_port_init(&self->port); - self->port.ops = &ircomm_port_ops; - self->magic = IRCOMM_TTY_MAGIC; - self->flow = FLOW_STOP; - - self->line = line; - INIT_WORK(&self->tqueue, ircomm_tty_do_softint); - self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED; - self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED; - - /* Init some important stuff */ - timer_setup(&self->watchdog_timer, NULL, 0); - spin_lock_init(&self->spinlock); - - /* - * Force TTY into raw mode by default which is usually what - * we want for IrCOMM and IrLPT. This way applications will - * not have to twiddle with printcap etc. - * - * Note this is completely usafe and doesn't work properly - */ - tty->termios.c_iflag = 0; - tty->termios.c_oflag = 0; - - /* Insert into hash */ - hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL); - } - - tty->driver_data = self; - - return tty_port_install(&self->port, driver, tty); -} - -/* - * Function ircomm_tty_open (tty, filp) - * - * This routine is called when a particular tty device is opened. This - * routine is mandatory; if this routine is not filled in, the attempted - * open will fail with ENODEV. - */ -static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) -{ - struct ircomm_tty_cb *self = tty->driver_data; - unsigned long flags; - int ret; - - /* ++ is not atomic, so this should be protected - Jean II */ - spin_lock_irqsave(&self->port.lock, flags); - self->port.count++; - spin_unlock_irqrestore(&self->port.lock, flags); - tty_port_tty_set(&self->port, tty); - - pr_debug("%s(), %s%d, count = %d\n", __func__ , tty->driver->name, - self->line, self->port.count); - - /* Not really used by us, but lets do it anyway */ - self->port.low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - /* Check if this is a "normal" ircomm device, or an irlpt device */ - if (self->line < 0x10) { - self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE; - self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */ - /* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */ - self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */ - pr_debug("%s(), IrCOMM device\n", __func__); - } else { - pr_debug("%s(), IrLPT device\n", __func__); - self->service_type = IRCOMM_3_WIRE_RAW; - self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */ - } - - ret = ircomm_tty_startup(self); - if (ret) - return ret; - - ret = ircomm_tty_block_til_ready(self, tty, filp); - if (ret) { - pr_debug("%s(), returning after block_til_ready with %d\n", - __func__, ret); - - return ret; - } - return 0; -} - -/* - * Function ircomm_tty_close (tty, filp) - * - * This routine is called when a particular tty device is closed. - * - */ -static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - struct tty_port *port = &self->port; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - if (tty_port_close_start(port, tty, filp) == 0) - return; - - ircomm_tty_shutdown(self); - - tty_driver_flush_buffer(tty); - - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); -} - -/* - * Function ircomm_tty_flush_buffer (tty) - * - * - * - */ -static void ircomm_tty_flush_buffer(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - /* - * Let do_softint() do this to avoid race condition with - * do_softint() ;-) - */ - schedule_work(&self->tqueue); -} - -/* - * Function ircomm_tty_do_softint (work) - * - * We use this routine to give the write wakeup to the user at at a - * safe time (as fast as possible after write have completed). This - * can be compared to the Tx interrupt. - */ -static void ircomm_tty_do_softint(struct work_struct *work) -{ - struct ircomm_tty_cb *self = - container_of(work, struct ircomm_tty_cb, tqueue); - struct tty_struct *tty; - unsigned long flags; - struct sk_buff *skb, *ctrl_skb; - - if (!self || self->magic != IRCOMM_TTY_MAGIC) - return; - - tty = tty_port_tty_get(&self->port); - if (!tty) - return; - - /* Unlink control buffer */ - spin_lock_irqsave(&self->spinlock, flags); - - ctrl_skb = self->ctrl_skb; - self->ctrl_skb = NULL; - - spin_unlock_irqrestore(&self->spinlock, flags); - - /* Flush control buffer if any */ - if(ctrl_skb) { - if(self->flow == FLOW_START) - ircomm_control_request(self->ircomm, ctrl_skb); - /* Drop reference count - see ircomm_ttp_data_request(). */ - dev_kfree_skb(ctrl_skb); - } - - if (tty->hw_stopped) - goto put; - - /* Unlink transmit buffer */ - spin_lock_irqsave(&self->spinlock, flags); - - skb = self->tx_skb; - self->tx_skb = NULL; - - spin_unlock_irqrestore(&self->spinlock, flags); - - /* Flush transmit buffer if any */ - if (skb) { - ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL); - /* Drop reference count - see ircomm_ttp_data_request(). */ - dev_kfree_skb(skb); - } - - /* Check if user (still) wants to be waken up */ - tty_wakeup(tty); -put: - tty_kref_put(tty); -} - -/* - * Function ircomm_tty_write (tty, buf, count) - * - * This routine is called by the kernel to write a series of characters - * to the tty device. The characters may come from user space or kernel - * space. This routine will return the number of characters actually - * accepted for writing. This routine is mandatory. - */ -static int ircomm_tty_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - unsigned long flags; - struct sk_buff *skb; - int tailroom = 0; - int len = 0; - int size; - - pr_debug("%s(), count=%d, hw_stopped=%d\n", __func__ , count, - tty->hw_stopped); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - /* We may receive packets from the TTY even before we have finished - * our setup. Not cool. - * The problem is that we don't know the final header and data size - * to create the proper skb, so any skb we would create would have - * bogus header and data size, so need care. - * We use a bogus header size to safely detect this condition. - * Another problem is that hw_stopped was set to 0 way before it - * should be, so we would drop this skb. It should now be fixed. - * One option is to not accept data until we are properly setup. - * But, I suspect that when it happens, the ppp line discipline - * just "drops" the data, which might screw up connect scripts. - * The second option is to create a "safe skb", with large header - * and small size (see ircomm_tty_open() for values). - * We just need to make sure that when the real values get filled, - * we don't mess up the original "safe skb" (see tx_data_size). - * Jean II */ - if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) { - pr_debug("%s() : not initialised\n", __func__); -#ifdef IRCOMM_NO_TX_BEFORE_INIT - /* We didn't consume anything, TTY will retry */ - return 0; -#endif - } - - if (count < 1) - return 0; - - /* Protect our manipulation of self->tx_skb and related */ - spin_lock_irqsave(&self->spinlock, flags); - - /* Fetch current transmit buffer */ - skb = self->tx_skb; - - /* - * Send out all the data we get, possibly as multiple fragmented - * frames, but this will only happen if the data is larger than the - * max data size. The normal case however is just the opposite, and - * this function may be called multiple times, and will then actually - * defragment the data and send it out as one packet as soon as - * possible, but at a safer point in time - */ - while (count) { - size = count; - - /* Adjust data size to the max data size */ - if (size > self->max_data_size) - size = self->max_data_size; - - /* - * Do we already have a buffer ready for transmit, or do - * we need to allocate a new frame - */ - if (skb) { - /* - * Any room for more data at the end of the current - * transmit buffer? Cannot use skb_tailroom, since - * dev_alloc_skb gives us a larger skb than we - * requested - * Note : use tx_data_size, because max_data_size - * may have changed and we don't want to overwrite - * the skb. - Jean II - */ - if ((tailroom = (self->tx_data_size - skb->len)) > 0) { - /* Adjust data to tailroom */ - if (size > tailroom) - size = tailroom; - } else { - /* - * Current transmit frame is full, so break - * out, so we can send it as soon as possible - */ - break; - } - } else { - /* Prepare a full sized frame */ - skb = alloc_skb(self->max_data_size+ - self->max_header_size, - GFP_ATOMIC); - if (!skb) { - spin_unlock_irqrestore(&self->spinlock, flags); - return -ENOBUFS; - } - skb_reserve(skb, self->max_header_size); - self->tx_skb = skb; - /* Remember skb size because max_data_size may - * change later on - Jean II */ - self->tx_data_size = self->max_data_size; - } - - /* Copy data */ - skb_put_data(skb, buf + len, size); - - count -= size; - len += size; - } - - spin_unlock_irqrestore(&self->spinlock, flags); - - /* - * Schedule a new thread which will transmit the frame as soon - * as possible, but at a safe point in time. We do this so the - * "user" can give us data multiple times, as PPP does (because of - * its 256 byte tx buffer). We will then defragment and send out - * all this data as one single packet. - */ - schedule_work(&self->tqueue); - - return len; -} - -/* - * Function ircomm_tty_write_room (tty) - * - * This routine returns the numbers of characters the tty driver will - * accept for queuing to be written. This number is subject to change as - * output buffers get emptied, or if the output flow control is acted. - */ -static int ircomm_tty_write_room(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - unsigned long flags; - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - -#ifdef IRCOMM_NO_TX_BEFORE_INIT - /* max_header_size tells us if the channel is initialised or not. */ - if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) - /* Don't bother us yet */ - return 0; -#endif - - /* Check if we are allowed to transmit any data. - * hw_stopped is the regular flow control. - * Jean II */ - if (tty->hw_stopped) - ret = 0; - else { - spin_lock_irqsave(&self->spinlock, flags); - if (self->tx_skb) - ret = self->tx_data_size - self->tx_skb->len; - else - ret = self->max_data_size; - spin_unlock_irqrestore(&self->spinlock, flags); - } - pr_debug("%s(), ret=%d\n", __func__ , ret); - - return ret; -} - -/* - * Function ircomm_tty_wait_until_sent (tty, timeout) - * - * This routine waits until the device has written out all of the - * characters in its transmitter FIFO. - */ -static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - unsigned long orig_jiffies, poll_time; - unsigned long flags; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - orig_jiffies = jiffies; - - /* Set poll time to 200 ms */ - poll_time = msecs_to_jiffies(200); - if (timeout) - poll_time = min_t(unsigned long, timeout, poll_time); - - spin_lock_irqsave(&self->spinlock, flags); - while (self->tx_skb && self->tx_skb->len) { - spin_unlock_irqrestore(&self->spinlock, flags); - schedule_timeout_interruptible(poll_time); - spin_lock_irqsave(&self->spinlock, flags); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - spin_unlock_irqrestore(&self->spinlock, flags); - __set_current_state(TASK_RUNNING); -} - -/* - * Function ircomm_tty_throttle (tty) - * - * This routine notifies the tty driver that input buffers for the line - * discipline are close to full, and it should somehow signal that no - * more characters should be sent to the tty. - */ -static void ircomm_tty_throttle(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - /* Software flow control? */ - if (I_IXOFF(tty)) - ircomm_tty_send_xchar(tty, STOP_CHAR(tty)); - - /* Hardware flow control? */ - if (C_CRTSCTS(tty)) { - self->settings.dte &= ~IRCOMM_RTS; - self->settings.dte |= IRCOMM_DELTA_RTS; - - ircomm_param_request(self, IRCOMM_DTE, TRUE); - } - - ircomm_flow_request(self->ircomm, FLOW_STOP); -} - -/* - * Function ircomm_tty_unthrottle (tty) - * - * This routine notifies the tty drivers that it should signals that - * characters can now be sent to the tty without fear of overrunning the - * input buffers of the line disciplines. - */ -static void ircomm_tty_unthrottle(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - /* Using software flow control? */ - if (I_IXOFF(tty)) - ircomm_tty_send_xchar(tty, START_CHAR(tty)); - - /* Using hardware flow control? */ - if (C_CRTSCTS(tty)) { - self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); - - ircomm_param_request(self, IRCOMM_DTE, TRUE); - pr_debug("%s(), FLOW_START\n", __func__); - } - ircomm_flow_request(self->ircomm, FLOW_START); -} - -/* - * Function ircomm_tty_chars_in_buffer (tty) - * - * Indicates if there are any data in the buffer - * - */ -static int ircomm_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - unsigned long flags; - int len = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - spin_lock_irqsave(&self->spinlock, flags); - - if (self->tx_skb) - len = self->tx_skb->len; - - spin_unlock_irqrestore(&self->spinlock, flags); - - return len; -} - -static void ircomm_tty_shutdown(struct ircomm_tty_cb *self) -{ - unsigned long flags; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - if (!tty_port_initialized(&self->port)) - return; - tty_port_set_initialized(&self->port, 0); - - ircomm_tty_detach_cable(self); - - spin_lock_irqsave(&self->spinlock, flags); - - del_timer(&self->watchdog_timer); - - /* Free parameter buffer */ - if (self->ctrl_skb) { - dev_kfree_skb(self->ctrl_skb); - self->ctrl_skb = NULL; - } - - /* Free transmit buffer */ - if (self->tx_skb) { - dev_kfree_skb(self->tx_skb); - self->tx_skb = NULL; - } - - if (self->ircomm) { - ircomm_close(self->ircomm); - self->ircomm = NULL; - } - - spin_unlock_irqrestore(&self->spinlock, flags); -} - -/* - * Function ircomm_tty_hangup (tty) - * - * This routine notifies the tty driver that it should hangup the tty - * device. - * - */ -static void ircomm_tty_hangup(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - struct tty_port *port = &self->port; - unsigned long flags; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - /* ircomm_tty_flush_buffer(tty); */ - ircomm_tty_shutdown(self); - - spin_lock_irqsave(&port->lock, flags); - if (port->tty) { - set_bit(TTY_IO_ERROR, &port->tty->flags); - tty_kref_put(port->tty); - } - port->tty = NULL; - port->count = 0; - spin_unlock_irqrestore(&port->lock, flags); - tty_port_set_active(port, 0); - - wake_up_interruptible(&port->open_wait); -} - -/* - * Function ircomm_tty_send_xchar (tty, ch) - * - * This routine is used to send a high-priority XON/XOFF character to - * the device. - */ -static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch) -{ - pr_debug("%s(), not impl\n", __func__); -} - -/* - * Function ircomm_tty_start (tty) - * - * This routine notifies the tty driver that it resume sending - * characters to the tty device. - */ -void ircomm_tty_start(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - - ircomm_flow_request(self->ircomm, FLOW_START); -} - -/* - * Function ircomm_tty_stop (tty) - * - * This routine notifies the tty driver that it should stop outputting - * characters to the tty device. - */ -static void ircomm_tty_stop(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - ircomm_flow_request(self->ircomm, FLOW_STOP); -} - -/* - * Function ircomm_check_modem_status (self) - * - * Check for any changes in the DCE's line settings. This function should - * be called whenever the dce parameter settings changes, to update the - * flow control settings and other things - */ -void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) -{ - struct tty_struct *tty; - int status; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - tty = tty_port_tty_get(&self->port); - - status = self->settings.dce; - - if (status & IRCOMM_DCE_DELTA_ANY) { - /*wake_up_interruptible(&self->delta_msr_wait);*/ - } - if (tty_port_check_carrier(&self->port) && (status & IRCOMM_DELTA_CD)) { - pr_debug("%s(), ircomm%d CD now %s...\n", __func__ , self->line, - (status & IRCOMM_CD) ? "on" : "off"); - - if (status & IRCOMM_CD) { - wake_up_interruptible(&self->port.open_wait); - } else { - pr_debug("%s(), Doing serial hangup..\n", __func__); - if (tty) - tty_hangup(tty); - - /* Hangup will remote the tty, so better break out */ - goto put; - } - } - if (tty && tty_port_cts_enabled(&self->port)) { - if (tty->hw_stopped) { - if (status & IRCOMM_CTS) { - pr_debug("%s(), CTS tx start...\n", __func__); - tty->hw_stopped = 0; - - /* Wake up processes blocked on open */ - wake_up_interruptible(&self->port.open_wait); - - schedule_work(&self->tqueue); - goto put; - } - } else { - if (!(status & IRCOMM_CTS)) { - pr_debug("%s(), CTS tx stop...\n", __func__); - tty->hw_stopped = 1; - } - } - } -put: - tty_kref_put(tty); -} - -/* - * Function ircomm_tty_data_indication (instance, sap, skb) - * - * Handle incoming data, and deliver it to the line discipline - * - */ -static int ircomm_tty_data_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - struct tty_struct *tty; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - tty = tty_port_tty_get(&self->port); - if (!tty) { - pr_debug("%s(), no tty!\n", __func__); - return 0; - } - - /* - * If we receive data when hardware is stopped then something is wrong. - * We try to poll the peers line settings to check if we are up todate. - * Devices like WinCE can do this, and since they don't send any - * params, we can just as well declare the hardware for running. - */ - if (tty->hw_stopped && (self->flow == FLOW_START)) { - pr_debug("%s(), polling for line settings!\n", __func__); - ircomm_param_request(self, IRCOMM_POLL, TRUE); - - /* We can just as well declare the hardware for running */ - ircomm_tty_send_initial_parameters(self); - ircomm_tty_link_established(self); - } - tty_kref_put(tty); - - /* - * Use flip buffer functions since the code may be called from interrupt - * context - */ - tty_insert_flip_string(&self->port, skb->data, skb->len); - tty_flip_buffer_push(&self->port); - - /* No need to kfree_skb - see ircomm_ttp_data_indication() */ - - return 0; -} - -/* - * Function ircomm_tty_control_indication (instance, sap, skb) - * - * Parse all incoming parameters (easy!) - * - */ -static int ircomm_tty_control_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - int clen; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - clen = skb->data[0]; - - irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen), - &ircomm_param_info); - - /* No need to kfree_skb - see ircomm_control_indication() */ - - return 0; -} - -/* - * Function ircomm_tty_flow_indication (instance, sap, cmd) - * - * This function is called by IrTTP when it wants us to slow down the - * transmission of data. We just mark the hardware as stopped, and wait - * for IrTTP to notify us that things are OK again. - */ -static void ircomm_tty_flow_indication(void *instance, void *sap, - LOCAL_FLOW cmd) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - struct tty_struct *tty; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - tty = tty_port_tty_get(&self->port); - - switch (cmd) { - case FLOW_START: - pr_debug("%s(), hw start!\n", __func__); - if (tty) - tty->hw_stopped = 0; - - /* ircomm_tty_do_softint will take care of the rest */ - schedule_work(&self->tqueue); - break; - default: /* If we get here, something is very wrong, better stop */ - case FLOW_STOP: - pr_debug("%s(), hw stopped!\n", __func__); - if (tty) - tty->hw_stopped = 1; - break; - } - - tty_kref_put(tty); - self->flow = cmd; -} - -#ifdef CONFIG_PROC_FS -static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m) -{ - struct tty_struct *tty; - char sep; - - seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]); - - seq_puts(m, "Service type: "); - if (self->service_type & IRCOMM_9_WIRE) - seq_puts(m, "9_WIRE"); - else if (self->service_type & IRCOMM_3_WIRE) - seq_puts(m, "3_WIRE"); - else if (self->service_type & IRCOMM_3_WIRE_RAW) - seq_puts(m, "3_WIRE_RAW"); - else - seq_puts(m, "No common service type!\n"); - seq_putc(m, '\n'); - - seq_printf(m, "Port name: %s\n", self->settings.port_name); - - seq_printf(m, "DTE status:"); - sep = ' '; - if (self->settings.dte & IRCOMM_RTS) { - seq_printf(m, "%cRTS", sep); - sep = '|'; - } - if (self->settings.dte & IRCOMM_DTR) { - seq_printf(m, "%cDTR", sep); - sep = '|'; - } - seq_putc(m, '\n'); - - seq_puts(m, "DCE status:"); - sep = ' '; - if (self->settings.dce & IRCOMM_CTS) { - seq_printf(m, "%cCTS", sep); - sep = '|'; - } - if (self->settings.dce & IRCOMM_DSR) { - seq_printf(m, "%cDSR", sep); - sep = '|'; - } - if (self->settings.dce & IRCOMM_CD) { - seq_printf(m, "%cCD", sep); - sep = '|'; - } - if (self->settings.dce & IRCOMM_RI) { - seq_printf(m, "%cRI", sep); - sep = '|'; - } - seq_putc(m, '\n'); - - seq_puts(m, "Configuration: "); - if (!self->settings.null_modem) - seq_puts(m, "DTE <-> DCE\n"); - else - seq_puts(m, "DTE <-> DTE (null modem emulation)\n"); - - seq_printf(m, "Data rate: %d\n", self->settings.data_rate); - - seq_puts(m, "Flow control:"); - sep = ' '; - if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) { - seq_printf(m, "%cXON_XOFF_IN", sep); - sep = '|'; - } - if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) { - seq_printf(m, "%cXON_XOFF_OUT", sep); - sep = '|'; - } - if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) { - seq_printf(m, "%cRTS_CTS_IN", sep); - sep = '|'; - } - if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) { - seq_printf(m, "%cRTS_CTS_OUT", sep); - sep = '|'; - } - if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) { - seq_printf(m, "%cDSR_DTR_IN", sep); - sep = '|'; - } - if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) { - seq_printf(m, "%cDSR_DTR_OUT", sep); - sep = '|'; - } - if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) { - seq_printf(m, "%cENQ_ACK_IN", sep); - sep = '|'; - } - if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) { - seq_printf(m, "%cENQ_ACK_OUT", sep); - sep = '|'; - } - seq_putc(m, '\n'); - - seq_puts(m, "Flags:"); - sep = ' '; - if (tty_port_cts_enabled(&self->port)) { - seq_printf(m, "%cASYNC_CTS_FLOW", sep); - sep = '|'; - } - if (tty_port_check_carrier(&self->port)) { - seq_printf(m, "%cASYNC_CHECK_CD", sep); - sep = '|'; - } - if (tty_port_initialized(&self->port)) { - seq_printf(m, "%cASYNC_INITIALIZED", sep); - sep = '|'; - } - if (self->port.flags & ASYNC_LOW_LATENCY) { - seq_printf(m, "%cASYNC_LOW_LATENCY", sep); - sep = '|'; - } - if (tty_port_active(&self->port)) { - seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep); - sep = '|'; - } - seq_putc(m, '\n'); - - seq_printf(m, "Role: %s\n", self->client ? "client" : "server"); - seq_printf(m, "Open count: %d\n", self->port.count); - seq_printf(m, "Max data size: %d\n", self->max_data_size); - seq_printf(m, "Max header size: %d\n", self->max_header_size); - - tty = tty_port_tty_get(&self->port); - if (tty) { - seq_printf(m, "Hardware: %s\n", - tty->hw_stopped ? "Stopped" : "Running"); - tty_kref_put(tty); - } -} - -static int ircomm_tty_proc_show(struct seq_file *m, void *v) -{ - struct ircomm_tty_cb *self; - unsigned long flags; - - spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags); - - self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); - while (self != NULL) { - if (self->magic != IRCOMM_TTY_MAGIC) - break; - - ircomm_tty_line_info(self, m); - self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty); - } - spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags); - return 0; -} - -static int ircomm_tty_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, ircomm_tty_proc_show, NULL); -} - -static const struct file_operations ircomm_tty_proc_fops = { - .owner = THIS_MODULE, - .open = ircomm_tty_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif /* CONFIG_PROC_FS */ - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("IrCOMM serial TTY driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(IRCOMM_TTY_MAJOR); - -module_init(ircomm_tty_init); -module_exit(ircomm_tty_cleanup); diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c b/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c deleted file mode 100644 index e2d5ce8ba0db..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_tty_attach.c +++ /dev/null @@ -1,987 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_tty_attach.c - * Version: - * Description: Code for attaching the serial driver to IrCOMM - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Jun 5 17:42:00 1999 - * Modified at: Tue Jan 4 14:20:49 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/init.h> -#include <linux/sched.h> - -#include <net/irda/irda.h> -#include <net/irda/irlmp.h> -#include <net/irda/iriap.h> -#include <net/irda/irttp.h> -#include <net/irda/irias_object.h> -#include <net/irda/parameters.h> - -#include <net/irda/ircomm_core.h> -#include <net/irda/ircomm_param.h> -#include <net/irda/ircomm_event.h> - -#include <net/irda/ircomm_tty.h> -#include <net/irda/ircomm_tty_attach.h> - -static void ircomm_tty_ias_register(struct ircomm_tty_cb *self); -static void ircomm_tty_discovery_indication(discinfo_t *discovery, - DISCOVERY_MODE mode, - void *priv); -static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, - struct ias_value *value, void *priv); -static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, - int timeout); -static void ircomm_tty_watchdog_timer_expired(struct timer_list *timer); - -static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info); -static int ircomm_tty_state_search(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info); -static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info); -static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info); -static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info); -static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info); - -const char *const ircomm_tty_state[] = { - "IRCOMM_TTY_IDLE", - "IRCOMM_TTY_SEARCH", - "IRCOMM_TTY_QUERY_PARAMETERS", - "IRCOMM_TTY_QUERY_LSAP_SEL", - "IRCOMM_TTY_SETUP", - "IRCOMM_TTY_READY", - "*** ERROR *** ", -}; - -static const char *const ircomm_tty_event[] __maybe_unused = { - "IRCOMM_TTY_ATTACH_CABLE", - "IRCOMM_TTY_DETACH_CABLE", - "IRCOMM_TTY_DATA_REQUEST", - "IRCOMM_TTY_DATA_INDICATION", - "IRCOMM_TTY_DISCOVERY_REQUEST", - "IRCOMM_TTY_DISCOVERY_INDICATION", - "IRCOMM_TTY_CONNECT_CONFIRM", - "IRCOMM_TTY_CONNECT_INDICATION", - "IRCOMM_TTY_DISCONNECT_REQUEST", - "IRCOMM_TTY_DISCONNECT_INDICATION", - "IRCOMM_TTY_WD_TIMER_EXPIRED", - "IRCOMM_TTY_GOT_PARAMETERS", - "IRCOMM_TTY_GOT_LSAPSEL", - "*** ERROR ****", -}; - -static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, - struct sk_buff *skb, struct ircomm_tty_info *info) = -{ - ircomm_tty_state_idle, - ircomm_tty_state_search, - ircomm_tty_state_query_parameters, - ircomm_tty_state_query_lsap_sel, - ircomm_tty_state_setup, - ircomm_tty_state_ready, -}; - -/* - * Function ircomm_tty_attach_cable (driver) - * - * Try to attach cable (IrCOMM link). This function will only return - * when the link has been connected, or if an error condition occurs. - * If success, the return value is the resulting service type. - */ -int ircomm_tty_attach_cable(struct ircomm_tty_cb *self) -{ - struct tty_struct *tty; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - /* Check if somebody has already connected to us */ - if (ircomm_is_connected(self->ircomm)) { - pr_debug("%s(), already connected!\n", __func__); - return 0; - } - - /* Make sure nobody tries to write before the link is up */ - tty = tty_port_tty_get(&self->port); - if (tty) { - tty->hw_stopped = 1; - tty_kref_put(tty); - } - - ircomm_tty_ias_register(self); - - ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL); - - return 0; -} - -/* - * Function ircomm_detach_cable (driver) - * - * Detach cable, or cable has been detached by peer - * - */ -void ircomm_tty_detach_cable(struct ircomm_tty_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - del_timer(&self->watchdog_timer); - - /* Remove discovery handler */ - if (self->ckey) { - irlmp_unregister_client(self->ckey); - self->ckey = NULL; - } - /* Remove IrCOMM hint bits */ - if (self->skey) { - irlmp_unregister_service(self->skey); - self->skey = NULL; - } - - if (self->iriap) { - iriap_close(self->iriap); - self->iriap = NULL; - } - - /* Remove LM-IAS object */ - if (self->obj) { - irias_delete_object(self->obj); - self->obj = NULL; - } - - ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL); - - /* Reset some values */ - self->daddr = self->saddr = 0; - self->dlsap_sel = self->slsap_sel = 0; - - memset(&self->settings, 0, sizeof(struct ircomm_params)); -} - -/* - * Function ircomm_tty_ias_register (self) - * - * Register with LM-IAS depending on which service type we are - * - */ -static void ircomm_tty_ias_register(struct ircomm_tty_cb *self) -{ - __u8 oct_seq[6]; - __u16 hints; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - /* Compute hint bits based on service */ - hints = irlmp_service_to_hint(S_COMM); - if (self->service_type & IRCOMM_3_WIRE_RAW) - hints |= irlmp_service_to_hint(S_PRINTER); - - /* Advertise IrCOMM hint bit in discovery */ - if (!self->skey) - self->skey = irlmp_register_service(hints); - /* Set up a discovery handler */ - if (!self->ckey) - self->ckey = irlmp_register_client(hints, - ircomm_tty_discovery_indication, - NULL, (void *) self); - - /* If already done, no need to do it again */ - if (self->obj) - return; - - if (self->service_type & IRCOMM_3_WIRE_RAW) { - /* Register IrLPT with LM-IAS */ - self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID); - irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", - self->slsap_sel, IAS_KERNEL_ATTR); - } else { - /* Register IrCOMM with LM-IAS */ - self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID); - irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", - self->slsap_sel, IAS_KERNEL_ATTR); - - /* Code the parameters into the buffer */ - irda_param_pack(oct_seq, "bbbbbb", - IRCOMM_SERVICE_TYPE, 1, self->service_type, - IRCOMM_PORT_TYPE, 1, IRCOMM_SERIAL); - - /* Register parameters with LM-IAS */ - irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6, - IAS_KERNEL_ATTR); - } - irias_insert_object(self->obj); -} - -/* - * Function ircomm_tty_ias_unregister (self) - * - * Remove our IAS object and client hook while connected. - * - */ -static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self) -{ - /* Remove LM-IAS object now so it is not reused. - * IrCOMM deals very poorly with multiple incoming connections. - * It should looks a lot more like IrNET, and "dup" a server TSAP - * to the application TSAP (based on various rules). - * This is a cheap workaround allowing multiple clients to - * connect to us. It will not always work. - * Each IrCOMM socket has an IAS entry. Incoming connection will - * pick the first one found. So, when we are fully connected, - * we remove our IAS entries so that the next IAS entry is used. - * We do that for *both* client and server, because a server - * can also create client instances. - * Jean II */ - if (self->obj) { - irias_delete_object(self->obj); - self->obj = NULL; - } - -#if 0 - /* Remove discovery handler. - * While we are connected, we no longer need to receive - * discovery events. This would be the case if there is - * multiple IrLAP interfaces. Jean II */ - if (self->ckey) { - irlmp_unregister_client(self->ckey); - self->ckey = NULL; - } -#endif -} - -/* - * Function ircomm_send_initial_parameters (self) - * - * Send initial parameters to the remote IrCOMM device. These parameters - * must be sent before any data. - */ -int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (self->service_type & IRCOMM_3_WIRE_RAW) - return 0; - - /* - * Set default values, but only if the application for some reason - * haven't set them already - */ - pr_debug("%s(), data-rate = %d\n", __func__ , - self->settings.data_rate); - if (!self->settings.data_rate) - self->settings.data_rate = 9600; - pr_debug("%s(), data-format = %d\n", __func__ , - self->settings.data_format); - if (!self->settings.data_format) - self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */ - - pr_debug("%s(), flow-control = %d\n", __func__ , - self->settings.flow_control); - /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/ - - /* Do not set delta values for the initial parameters */ - self->settings.dte = IRCOMM_DTR | IRCOMM_RTS; - - /* Only send service type parameter when we are the client */ - if (self->client) - ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE); - ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE); - ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE); - - /* For a 3 wire service, we just flush the last parameter and return */ - if (self->settings.service_type == IRCOMM_3_WIRE) { - ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE); - return 0; - } - - /* Only 9-wire service types continue here */ - ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE); -#if 0 - ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE); - ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE); -#endif - /* Notify peer that we are ready to receive data */ - ircomm_param_request(self, IRCOMM_DTE, TRUE); - - return 0; -} - -/* - * Function ircomm_tty_discovery_indication (discovery) - * - * Remote device is discovered, try query the remote IAS to see which - * device it is, and which services it has. - * - */ -static void ircomm_tty_discovery_indication(discinfo_t *discovery, - DISCOVERY_MODE mode, - void *priv) -{ - struct ircomm_tty_cb *self; - struct ircomm_tty_info info; - - /* Important note : - * We need to drop all passive discoveries. - * The LSAP management of IrComm is deficient and doesn't deal - * with the case of two instance connecting to each other - * simultaneously (it will deadlock in LMP). - * The proper fix would be to use the same technique as in IrNET, - * to have one server socket and separate instances for the - * connecting/connected socket. - * The workaround is to drop passive discovery, which drastically - * reduce the probability of this happening. - * Jean II */ - if(mode == DISCOVERY_PASSIVE) - return; - - info.daddr = discovery->daddr; - info.saddr = discovery->saddr; - - self = priv; - ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, - NULL, &info); -} - -/* - * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb) - * - * Link disconnected - * - */ -void ircomm_tty_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *skb) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - struct tty_struct *tty; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - tty = tty_port_tty_get(&self->port); - if (!tty) - return; - - /* This will stop control data transfers */ - self->flow = FLOW_STOP; - - /* Stop data transfers */ - tty->hw_stopped = 1; - - ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL, - NULL); - tty_kref_put(tty); -} - -/* - * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv) - * - * Got result from the IAS query we make - * - */ -static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, - struct ias_value *value, - void *priv) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - /* We probably don't need to make any more queries */ - iriap_close(self->iriap); - self->iriap = NULL; - - /* Check if request succeeded */ - if (result != IAS_SUCCESS) { - pr_debug("%s(), got NULL value!\n", __func__); - return; - } - - switch (value->type) { - case IAS_OCT_SEQ: - pr_debug("%s(), got octet sequence\n", __func__); - - irda_param_extract_all(self, value->t.oct_seq, value->len, - &ircomm_param_info); - - ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL, - NULL); - break; - case IAS_INTEGER: - /* Got LSAP selector */ - pr_debug("%s(), got lsapsel = %d\n", __func__ , - value->t.integer); - - if (value->t.integer == -1) { - pr_debug("%s(), invalid value!\n", __func__); - } else - self->dlsap_sel = value->t.integer; - - ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL); - break; - case IAS_MISSING: - pr_debug("%s(), got IAS_MISSING\n", __func__); - break; - default: - pr_debug("%s(), got unknown type!\n", __func__); - break; - } - irias_delete_value(value); -} - -/* - * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb) - * - * Connection confirmed - * - */ -void ircomm_tty_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_data_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - self->client = TRUE; - self->max_data_size = max_data_size; - self->max_header_size = max_header_size; - self->flow = FLOW_START; - - ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL); - - /* No need to kfree_skb - see ircomm_ttp_connect_confirm() */ -} - -/* - * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size, - * skb) - * - * we are discovered and being requested to connect by remote device ! - * - */ -void ircomm_tty_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_data_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - int clen; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - self->client = FALSE; - self->max_data_size = max_data_size; - self->max_header_size = max_header_size; - self->flow = FLOW_START; - - clen = skb->data[0]; - if (clen) - irda_param_extract_all(self, skb->data+1, - IRDA_MIN(skb->len, clen), - &ircomm_param_info); - - ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL); - - /* No need to kfree_skb - see ircomm_ttp_connect_indication() */ -} - -/* - * Function ircomm_tty_link_established (self) - * - * Called when the IrCOMM link is established - * - */ -void ircomm_tty_link_established(struct ircomm_tty_cb *self) -{ - struct tty_struct *tty; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - tty = tty_port_tty_get(&self->port); - if (!tty) - return; - - del_timer(&self->watchdog_timer); - - /* - * IrCOMM link is now up, and if we are not using hardware - * flow-control, then declare the hardware as running. Otherwise we - * will have to wait for the peer device (DCE) to raise the CTS - * line. - */ - if (tty_port_cts_enabled(&self->port) && - ((self->settings.dce & IRCOMM_CTS) == 0)) { - pr_debug("%s(), waiting for CTS ...\n", __func__); - goto put; - } else { - pr_debug("%s(), starting hardware!\n", __func__); - - tty->hw_stopped = 0; - - /* Wake up processes blocked on open */ - wake_up_interruptible(&self->port.open_wait); - } - - schedule_work(&self->tqueue); -put: - tty_kref_put(tty); -} - -/* - * Function ircomm_tty_start_watchdog_timer (self, timeout) - * - * Start the watchdog timer. This timer is used to make sure that any - * connection attempt is successful, and if not, we will retry after - * the timeout - */ -static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, - int timeout) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - irda_start_timer(&self->watchdog_timer, timeout, - ircomm_tty_watchdog_timer_expired); -} - -/* - * Function ircomm_tty_watchdog_timer_expired (data) - * - * Called when the connect procedure have taken to much time. - * - */ -static void ircomm_tty_watchdog_timer_expired(struct timer_list *t) -{ - struct ircomm_tty_cb *self = from_timer(self, t, watchdog_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL); -} - - -/* - * Function ircomm_tty_do_event (self, event, skb) - * - * Process event - * - */ -int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, - struct sk_buff *skb, struct ircomm_tty_info *info) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - pr_debug("%s: state=%s, event=%s\n", __func__ , - ircomm_tty_state[self->state], ircomm_tty_event[event]); - - return (*state[self->state])(self, event, skb, info); -} - -/* - * Function ircomm_tty_next_state (self, state) - * - * Switch state - * - */ -static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state) -{ - /* - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - - pr_debug("%s: next state=%s, service type=%d\n", __func__ , - ircomm_tty_state[self->state], self->service_type); - */ - self->state = state; -} - -/* - * Function ircomm_tty_state_idle (self, event, skb, info) - * - * Just hanging around - * - */ -static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info) -{ - int ret = 0; - - pr_debug("%s: state=%s, event=%s\n", __func__ , - ircomm_tty_state[self->state], ircomm_tty_event[event]); - switch (event) { - case IRCOMM_TTY_ATTACH_CABLE: - /* Try to discover any remote devices */ - ircomm_tty_start_watchdog_timer(self, 3*HZ); - ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); - - irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); - break; - case IRCOMM_TTY_DISCOVERY_INDICATION: - self->daddr = info->daddr; - self->saddr = info->saddr; - - if (self->iriap) { - net_warn_ratelimited("%s(), busy with a previous query\n", - __func__); - return -EBUSY; - } - - self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - ircomm_tty_getvalue_confirm); - - iriap_getvaluebyclass_request(self->iriap, - self->saddr, self->daddr, - "IrDA:IrCOMM", "Parameters"); - - ircomm_tty_start_watchdog_timer(self, 3*HZ); - ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS); - break; - case IRCOMM_TTY_CONNECT_INDICATION: - del_timer(&self->watchdog_timer); - - /* Accept connection */ - ircomm_connect_response(self->ircomm, NULL); - ircomm_tty_next_state(self, IRCOMM_TTY_READY); - break; - case IRCOMM_TTY_WD_TIMER_EXPIRED: - /* Just stay idle */ - break; - case IRCOMM_TTY_DETACH_CABLE: - ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_tty_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_tty_state_search (self, event, skb, info) - * - * Trying to discover an IrCOMM device - * - */ -static int ircomm_tty_state_search(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info) -{ - int ret = 0; - - pr_debug("%s: state=%s, event=%s\n", __func__ , - ircomm_tty_state[self->state], ircomm_tty_event[event]); - - switch (event) { - case IRCOMM_TTY_DISCOVERY_INDICATION: - self->daddr = info->daddr; - self->saddr = info->saddr; - - if (self->iriap) { - net_warn_ratelimited("%s(), busy with a previous query\n", - __func__); - return -EBUSY; - } - - self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - ircomm_tty_getvalue_confirm); - - if (self->service_type == IRCOMM_3_WIRE_RAW) { - iriap_getvaluebyclass_request(self->iriap, self->saddr, - self->daddr, "IrLPT", - "IrDA:IrLMP:LsapSel"); - ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL); - } else { - iriap_getvaluebyclass_request(self->iriap, self->saddr, - self->daddr, - "IrDA:IrCOMM", - "Parameters"); - - ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS); - } - ircomm_tty_start_watchdog_timer(self, 3*HZ); - break; - case IRCOMM_TTY_CONNECT_INDICATION: - del_timer(&self->watchdog_timer); - ircomm_tty_ias_unregister(self); - - /* Accept connection */ - ircomm_connect_response(self->ircomm, NULL); - ircomm_tty_next_state(self, IRCOMM_TTY_READY); - break; - case IRCOMM_TTY_WD_TIMER_EXPIRED: -#if 1 - /* Give up */ -#else - /* Try to discover any remote devices */ - ircomm_tty_start_watchdog_timer(self, 3*HZ); - irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); -#endif - break; - case IRCOMM_TTY_DETACH_CABLE: - ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_tty_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_tty_state_query (self, event, skb, info) - * - * Querying the remote LM-IAS for IrCOMM parameters - * - */ -static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info) -{ - int ret = 0; - - pr_debug("%s: state=%s, event=%s\n", __func__ , - ircomm_tty_state[self->state], ircomm_tty_event[event]); - - switch (event) { - case IRCOMM_TTY_GOT_PARAMETERS: - if (self->iriap) { - net_warn_ratelimited("%s(), busy with a previous query\n", - __func__); - return -EBUSY; - } - - self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - ircomm_tty_getvalue_confirm); - - iriap_getvaluebyclass_request(self->iriap, self->saddr, - self->daddr, "IrDA:IrCOMM", - "IrDA:TinyTP:LsapSel"); - - ircomm_tty_start_watchdog_timer(self, 3*HZ); - ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL); - break; - case IRCOMM_TTY_WD_TIMER_EXPIRED: - /* Go back to search mode */ - ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); - ircomm_tty_start_watchdog_timer(self, 3*HZ); - break; - case IRCOMM_TTY_CONNECT_INDICATION: - del_timer(&self->watchdog_timer); - ircomm_tty_ias_unregister(self); - - /* Accept connection */ - ircomm_connect_response(self->ircomm, NULL); - ircomm_tty_next_state(self, IRCOMM_TTY_READY); - break; - case IRCOMM_TTY_DETACH_CABLE: - ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_tty_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info) - * - * Query remote LM-IAS for the LSAP selector which we can connect to - * - */ -static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info) -{ - int ret = 0; - - pr_debug("%s: state=%s, event=%s\n", __func__ , - ircomm_tty_state[self->state], ircomm_tty_event[event]); - - switch (event) { - case IRCOMM_TTY_GOT_LSAPSEL: - /* Connect to remote device */ - ret = ircomm_connect_request(self->ircomm, self->dlsap_sel, - self->saddr, self->daddr, - NULL, self->service_type); - ircomm_tty_start_watchdog_timer(self, 3*HZ); - ircomm_tty_next_state(self, IRCOMM_TTY_SETUP); - break; - case IRCOMM_TTY_WD_TIMER_EXPIRED: - /* Go back to search mode */ - ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); - ircomm_tty_start_watchdog_timer(self, 3*HZ); - break; - case IRCOMM_TTY_CONNECT_INDICATION: - del_timer(&self->watchdog_timer); - ircomm_tty_ias_unregister(self); - - /* Accept connection */ - ircomm_connect_response(self->ircomm, NULL); - ircomm_tty_next_state(self, IRCOMM_TTY_READY); - break; - case IRCOMM_TTY_DETACH_CABLE: - ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_tty_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_tty_state_setup (self, event, skb, info) - * - * Trying to connect - * - */ -static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info) -{ - int ret = 0; - - pr_debug("%s: state=%s, event=%s\n", __func__ , - ircomm_tty_state[self->state], ircomm_tty_event[event]); - - switch (event) { - case IRCOMM_TTY_CONNECT_CONFIRM: - del_timer(&self->watchdog_timer); - ircomm_tty_ias_unregister(self); - - /* - * Send initial parameters. This will also send out queued - * parameters waiting for the connection to come up - */ - ircomm_tty_send_initial_parameters(self); - ircomm_tty_link_established(self); - ircomm_tty_next_state(self, IRCOMM_TTY_READY); - break; - case IRCOMM_TTY_CONNECT_INDICATION: - del_timer(&self->watchdog_timer); - ircomm_tty_ias_unregister(self); - - /* Accept connection */ - ircomm_connect_response(self->ircomm, NULL); - ircomm_tty_next_state(self, IRCOMM_TTY_READY); - break; - case IRCOMM_TTY_WD_TIMER_EXPIRED: - /* Go back to search mode */ - ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); - ircomm_tty_start_watchdog_timer(self, 3*HZ); - break; - case IRCOMM_TTY_DETACH_CABLE: - /* ircomm_disconnect_request(self->ircomm, NULL); */ - ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_tty_event[event]); - ret = -EINVAL; - } - return ret; -} - -/* - * Function ircomm_tty_state_ready (self, event, skb, info) - * - * IrCOMM is now connected - * - */ -static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, - IRCOMM_TTY_EVENT event, - struct sk_buff *skb, - struct ircomm_tty_info *info) -{ - int ret = 0; - - switch (event) { - case IRCOMM_TTY_DATA_REQUEST: - ret = ircomm_data_request(self->ircomm, skb); - break; - case IRCOMM_TTY_DETACH_CABLE: - ircomm_disconnect_request(self->ircomm, NULL); - ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); - break; - case IRCOMM_TTY_DISCONNECT_INDICATION: - ircomm_tty_ias_register(self); - ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH); - ircomm_tty_start_watchdog_timer(self, 3*HZ); - - if (tty_port_check_carrier(&self->port)) { - /* Drop carrier */ - self->settings.dce = IRCOMM_DELTA_CD; - ircomm_tty_check_modem_status(self); - } else { - pr_debug("%s(), hanging up!\n", __func__); - tty_port_tty_hangup(&self->port, false); - } - break; - default: - pr_debug("%s(), unknown event: %s\n", __func__ , - ircomm_tty_event[event]); - ret = -EINVAL; - } - return ret; -} - diff --git a/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c b/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c deleted file mode 100644 index 171c3dee760e..000000000000 --- a/drivers/staging/irda/net/ircomm/ircomm_tty_ioctl.c +++ /dev/null @@ -1,291 +0,0 @@ -/********************************************************************* - * - * Filename: ircomm_tty_ioctl.c - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Jun 10 14:39:09 1999 - * Modified at: Wed Jan 5 14:45:43 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/termios.h> -#include <linux/tty.h> -#include <linux/serial.h> - -#include <linux/uaccess.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> - -#include <net/irda/ircomm_core.h> -#include <net/irda/ircomm_param.h> -#include <net/irda/ircomm_tty_attach.h> -#include <net/irda/ircomm_tty.h> - -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -/* - * Function ircomm_tty_change_speed (driver) - * - * Change speed of the driver. If the remote device is a DCE, then this - * should make it change the speed of its serial port - */ -static void ircomm_tty_change_speed(struct ircomm_tty_cb *self, - struct tty_struct *tty) -{ - unsigned int cflag, cval; - int baud; - - if (!self->ircomm) - return; - - cflag = tty->termios.c_cflag; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: cval = IRCOMM_WSIZE_5; break; - case CS6: cval = IRCOMM_WSIZE_6; break; - case CS7: cval = IRCOMM_WSIZE_7; break; - case CS8: cval = IRCOMM_WSIZE_8; break; - default: cval = IRCOMM_WSIZE_5; break; - } - if (cflag & CSTOPB) - cval |= IRCOMM_2_STOP_BIT; - - if (cflag & PARENB) - cval |= IRCOMM_PARITY_ENABLE; - if (!(cflag & PARODD)) - cval |= IRCOMM_PARITY_EVEN; - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(tty); - if (!baud) - baud = 9600; /* B0 transition handled in rs_set_termios */ - - self->settings.data_rate = baud; - ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE); - - /* CTS flow control flag and modem status interrupts */ - tty_port_set_cts_flow(&self->port, cflag & CRTSCTS); - if (cflag & CRTSCTS) { - self->settings.flow_control |= IRCOMM_RTS_CTS_IN; - /* This got me. Bummer. Jean II */ - if (self->service_type == IRCOMM_3_WIRE_RAW) - net_warn_ratelimited("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", - __func__); - } else { - self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN; - } - tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL); - - self->settings.data_format = cval; - - ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE); - ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE); -} - -/* - * Function ircomm_tty_set_termios (tty, old_termios) - * - * This routine allows the tty driver to be notified when device's - * termios settings have changed. Note that a well-designed tty driver - * should be prepared to accept the case where old == NULL, and try to - * do something rational. - */ -void ircomm_tty_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - unsigned int cflag = tty->termios.c_cflag; - - if ((cflag == old_termios->c_cflag) && - (RELEVANT_IFLAG(tty->termios.c_iflag) == - RELEVANT_IFLAG(old_termios->c_iflag))) - { - return; - } - - ircomm_tty_change_speed(self, tty); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) { - self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS); - ircomm_param_request(self, IRCOMM_DTE, TRUE); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { - self->settings.dte |= IRCOMM_DTR; - if (!C_CRTSCTS(tty) || !tty_throttled(tty)) - self->settings.dte |= IRCOMM_RTS; - ircomm_param_request(self, IRCOMM_DTE, TRUE); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) - { - tty->hw_stopped = 0; - ircomm_tty_start(tty); - } -} - -/* - * Function ircomm_tty_tiocmget (tty) - * - * - * - */ -int ircomm_tty_tiocmget(struct tty_struct *tty) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - unsigned int result; - - if (tty_io_error(tty)) - return -EIO; - - result = ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0) - | ((self->settings.dte & IRCOMM_DTR) ? TIOCM_DTR : 0) - | ((self->settings.dce & IRCOMM_CD) ? TIOCM_CAR : 0) - | ((self->settings.dce & IRCOMM_RI) ? TIOCM_RNG : 0) - | ((self->settings.dce & IRCOMM_DSR) ? TIOCM_DSR : 0) - | ((self->settings.dce & IRCOMM_CTS) ? TIOCM_CTS : 0); - return result; -} - -/* - * Function ircomm_tty_tiocmset (tty, set, clear) - * - * - * - */ -int ircomm_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - - if (tty_io_error(tty)) - return -EIO; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - - if (set & TIOCM_RTS) - self->settings.dte |= IRCOMM_RTS; - if (set & TIOCM_DTR) - self->settings.dte |= IRCOMM_DTR; - - if (clear & TIOCM_RTS) - self->settings.dte &= ~IRCOMM_RTS; - if (clear & TIOCM_DTR) - self->settings.dte &= ~IRCOMM_DTR; - - if ((set|clear) & TIOCM_RTS) - self->settings.dte |= IRCOMM_DELTA_RTS; - if ((set|clear) & TIOCM_DTR) - self->settings.dte |= IRCOMM_DELTA_DTR; - - ircomm_param_request(self, IRCOMM_DTE, TRUE); - - return 0; -} - -/* - * Function get_serial_info (driver, retinfo) - * - * - * - */ -static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self, - struct serial_struct __user *retinfo) -{ - struct serial_struct info; - - memset(&info, 0, sizeof(info)); - info.line = self->line; - info.flags = self->port.flags; - info.baud_base = self->settings.data_rate; - info.close_delay = self->port.close_delay; - info.closing_wait = self->port.closing_wait; - - /* For compatibility */ - info.type = PORT_16550A; - - if (copy_to_user(retinfo, &info, sizeof(*retinfo))) - return -EFAULT; - - return 0; -} - -/* - * Function set_serial_info (driver, new_info) - * - * - * - */ -static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self, - struct serial_struct __user *new_info) -{ - return 0; -} - -/* - * Function ircomm_tty_ioctl (tty, cmd, arg) - * - * - * - */ -int ircomm_tty_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - int ret = 0; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && - (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty_io_error(tty)) - return -EIO; - } - - switch (cmd) { - case TIOCGSERIAL: - ret = ircomm_tty_get_serial_info(self, (struct serial_struct __user *) arg); - break; - case TIOCSSERIAL: - ret = ircomm_tty_set_serial_info(self, (struct serial_struct __user *) arg); - break; - case TIOCMIWAIT: - pr_debug("(), TIOCMIWAIT, not impl!\n"); - break; - - case TIOCGICOUNT: - pr_debug("%s(), TIOCGICOUNT not impl!\n", __func__); - return 0; - default: - ret = -ENOIOCTLCMD; /* ioctls which we must ignore */ - } - return ret; -} - - - diff --git a/drivers/staging/irda/net/irda_device.c b/drivers/staging/irda/net/irda_device.c deleted file mode 100644 index 682b4eea15e0..000000000000 --- a/drivers/staging/irda/net/irda_device.c +++ /dev/null @@ -1,316 +0,0 @@ -/********************************************************************* - * - * Filename: irda_device.c - * Version: 0.9 - * Description: Utility functions used by the device drivers - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Oct 9 09:22:27 1999 - * Modified at: Sun Jan 23 17:41:24 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/string.h> -#include <linux/proc_fs.h> -#include <linux/skbuff.h> -#include <linux/capability.h> -#include <linux/if.h> -#include <linux/if_ether.h> -#include <linux/if_arp.h> -#include <linux/netdevice.h> -#include <linux/init.h> -#include <linux/tty.h> -#include <linux/kmod.h> -#include <linux/spinlock.h> -#include <linux/slab.h> -#include <linux/export.h> - -#include <asm/ioctls.h> -#include <linux/uaccess.h> -#include <asm/dma.h> -#include <asm/io.h> - -#include <net/irda/irda_device.h> -#include <net/irda/irlap.h> -#include <net/irda/timer.h> -#include <net/irda/wrapper.h> - -static void __irda_task_delete(struct irda_task *task); - -static hashbin_t *dongles; -static hashbin_t *tasks; - -static void irda_task_timer_expired(struct timer_list *timer); - -int __init irda_device_init(void) -{ - dongles = hashbin_new(HB_NOLOCK); - if (!dongles) { - net_warn_ratelimited("IrDA: Can't allocate dongles hashbin!\n"); - return -ENOMEM; - } - spin_lock_init(&dongles->hb_spinlock); - - tasks = hashbin_new(HB_LOCK); - if (!tasks) { - net_warn_ratelimited("IrDA: Can't allocate tasks hashbin!\n"); - hashbin_delete(dongles, NULL); - return -ENOMEM; - } - - /* We no longer initialise the driver ourselves here, we let - * the system do it for us... - Jean II - */ - - return 0; -} - -static void leftover_dongle(void *arg) -{ - struct dongle_reg *reg = arg; - - net_warn_ratelimited("IrDA: Dongle type %x not unregistered\n", - reg->type); -} - -void irda_device_cleanup(void) -{ - hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete); - - hashbin_delete(dongles, leftover_dongle); -} - -/* - * Function irda_device_set_media_busy (self, status) - * - * Called when we have detected that another station is transmitting - * in contention mode. - */ -void irda_device_set_media_busy(struct net_device *dev, int status) -{ - struct irlap_cb *self; - - pr_debug("%s(%s)\n", __func__, status ? "TRUE" : "FALSE"); - - self = (struct irlap_cb *)dev->atalk_ptr; - - /* Some drivers may enable the receive interrupt before calling - * irlap_open(), or they may disable the receive interrupt - * after calling irlap_close(). - * The IrDA stack is protected from this in irlap_driver_rcv(). - * However, the driver calls directly the wrapper, that calls - * us directly. Make sure we protect ourselves. - * Jean II - */ - if (!self || self->magic != LAP_MAGIC) - return; - - if (status) { - self->media_busy = TRUE; - if (status == SMALL) - irlap_start_mbusy_timer(self, SMALLBUSY_TIMEOUT); - else - irlap_start_mbusy_timer(self, MEDIABUSY_TIMEOUT); - pr_debug("Media busy!\n"); - } else { - self->media_busy = FALSE; - irlap_stop_mbusy_timer(self); - } -} -EXPORT_SYMBOL(irda_device_set_media_busy); - -/* - * Function irda_device_is_receiving (dev) - * - * Check if the device driver is currently receiving data - * - */ -int irda_device_is_receiving(struct net_device *dev) -{ - struct if_irda_req req; - int ret; - - if (!dev->netdev_ops->ndo_do_ioctl) { - net_err_ratelimited("%s: do_ioctl not impl. by device driver\n", - __func__); - return -1; - } - - ret = (dev->netdev_ops->ndo_do_ioctl)(dev, (struct ifreq *) &req, - SIOCGRECEIVING); - if (ret < 0) - return ret; - - return req.ifr_receiving; -} - -static void __irda_task_delete(struct irda_task *task) -{ - del_timer(&task->timer); - - kfree(task); -} - -static void irda_task_delete(struct irda_task *task) -{ - /* Unregister task */ - hashbin_remove(tasks, (long)task, NULL); - - __irda_task_delete(task); -} - -/* - * Function irda_task_kick (task) - * - * Tries to execute a task possible multiple times until the task is either - * finished, or askes for a timeout. When a task is finished, we do post - * processing, and notify the parent task, that is waiting for this task - * to complete. - */ -static int irda_task_kick(struct irda_task *task) -{ - int finished = TRUE; - int count = 0; - int timeout; - - IRDA_ASSERT(task != NULL, return -1;); - IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;); - - /* Execute task until it's finished, or askes for a timeout */ - do { - timeout = task->function(task); - if (count++ > 100) { - net_err_ratelimited("%s: error in task handler!\n", - __func__); - irda_task_delete(task); - return TRUE; - } - } while ((timeout == 0) && (task->state != IRDA_TASK_DONE)); - - if (timeout < 0) { - net_err_ratelimited("%s: Error executing task!\n", __func__); - irda_task_delete(task); - return TRUE; - } - - /* Check if we are finished */ - if (task->state == IRDA_TASK_DONE) { - del_timer(&task->timer); - - /* Do post processing */ - if (task->finished) - task->finished(task); - - /* Notify parent */ - if (task->parent) { - /* Check if parent is waiting for us to complete */ - if (task->parent->state == IRDA_TASK_CHILD_WAIT) { - task->parent->state = IRDA_TASK_CHILD_DONE; - - /* Stop timer now that we are here */ - del_timer(&task->parent->timer); - - /* Kick parent task */ - irda_task_kick(task->parent); - } - } - irda_task_delete(task); - } else if (timeout > 0) { - irda_start_timer(&task->timer, timeout, - irda_task_timer_expired); - finished = FALSE; - } else { - pr_debug("%s(), not finished, and no timeout!\n", - __func__); - finished = FALSE; - } - - return finished; -} - -/* - * Function irda_task_timer_expired (data) - * - * Task time has expired. We now try to execute task (again), and restart - * the timer if the task has not finished yet - */ -static void irda_task_timer_expired(struct timer_list *t) -{ - struct irda_task *task = from_timer(task, t, timer); - - irda_task_kick(task); -} - -/* - * Function irda_device_setup (dev) - * - * This function should be used by low level device drivers in a similar way - * as ether_setup() is used by normal network device drivers - */ -static void irda_device_setup(struct net_device *dev) -{ - dev->hard_header_len = 0; - dev->addr_len = LAP_ALEN; - - dev->type = ARPHRD_IRDA; - dev->tx_queue_len = 8; /* Window size + 1 s-frame */ - - memset(dev->broadcast, 0xff, LAP_ALEN); - - dev->mtu = 2048; - dev->flags = IFF_NOARP; -} - -/* - * Funciton alloc_irdadev - * Allocates and sets up an IRDA device in a manner similar to - * alloc_etherdev. - */ -struct net_device *alloc_irdadev(int sizeof_priv) -{ - return alloc_netdev(sizeof_priv, "irda%d", NET_NAME_UNKNOWN, - irda_device_setup); -} -EXPORT_SYMBOL(alloc_irdadev); - -#ifdef CONFIG_ISA_DMA_API -/* - * Function setup_dma (idev, buffer, count, mode) - * - * Setup the DMA channel. Commonly used by LPC FIR drivers - * - */ -void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode) -{ - unsigned long flags; - - flags = claim_dma_lock(); - - disable_dma(channel); - clear_dma_ff(channel); - set_dma_mode(channel, mode); - set_dma_addr(channel, buffer); - set_dma_count(channel, count); - enable_dma(channel); - - release_dma_lock(flags); -} -EXPORT_SYMBOL(irda_setup_dma); -#endif diff --git a/drivers/staging/irda/net/iriap.c b/drivers/staging/irda/net/iriap.c deleted file mode 100644 index d64192e9db8b..000000000000 --- a/drivers/staging/irda/net/iriap.c +++ /dev/null @@ -1,1085 +0,0 @@ -/********************************************************************* - * - * Filename: iriap.c - * Version: 0.8 - * Description: Information Access Protocol (IAP) - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Aug 21 00:02:07 1997 - * Modified at: Sat Dec 25 16:42:42 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/skbuff.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/seq_file.h> -#include <linux/slab.h> - -#include <asm/byteorder.h> -#include <asm/unaligned.h> - -#include <net/irda/irda.h> -#include <net/irda/irttp.h> -#include <net/irda/irlmp.h> -#include <net/irda/irias_object.h> -#include <net/irda/iriap_event.h> -#include <net/irda/iriap.h> - -/* FIXME: This one should go in irlmp.c */ -static const char *const ias_charset_types[] __maybe_unused = { - "CS_ASCII", - "CS_ISO_8859_1", - "CS_ISO_8859_2", - "CS_ISO_8859_3", - "CS_ISO_8859_4", - "CS_ISO_8859_5", - "CS_ISO_8859_6", - "CS_ISO_8859_7", - "CS_ISO_8859_8", - "CS_ISO_8859_9", - "CS_UNICODE" -}; - -static hashbin_t *iriap = NULL; -static void *service_handle; - -static void __iriap_close(struct iriap_cb *self); -static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode); -static void iriap_disconnect_indication(void *instance, void *sap, - LM_REASON reason, struct sk_buff *skb); -static void iriap_connect_indication(void *instance, void *sap, - struct qos_info *qos, __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb); -static void iriap_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, __u8 max_header_size, - struct sk_buff *skb); -static int iriap_data_indication(void *instance, void *sap, - struct sk_buff *skb); - -static void iriap_watchdog_timer_expired(struct timer_list *t); - -static inline void iriap_start_watchdog_timer(struct iriap_cb *self, - int timeout) -{ - irda_start_timer(&self->watchdog_timer, timeout, - iriap_watchdog_timer_expired); -} - -static struct lock_class_key irias_objects_key; - -/* - * Function iriap_init (void) - * - * Initializes the IrIAP layer, called by the module initialization code - * in irmod.c - */ -int __init iriap_init(void) -{ - struct ias_object *obj; - struct iriap_cb *server; - __u8 oct_seq[6]; - __u16 hints; - - /* Allocate master array */ - iriap = hashbin_new(HB_LOCK); - if (!iriap) - return -ENOMEM; - - /* Object repository - defined in irias_object.c */ - irias_objects = hashbin_new(HB_LOCK); - if (!irias_objects) { - net_warn_ratelimited("%s: Can't allocate irias_objects hashbin!\n", - __func__); - hashbin_delete(iriap, NULL); - return -ENOMEM; - } - - lockdep_set_class_and_name(&irias_objects->hb_spinlock, &irias_objects_key, - "irias_objects"); - - /* - * Register some default services for IrLMP - */ - hints = irlmp_service_to_hint(S_COMPUTER); - service_handle = irlmp_register_service(hints); - - /* Register the Device object with LM-IAS */ - obj = irias_new_object("Device", IAS_DEVICE_ID); - irias_add_string_attrib(obj, "DeviceName", "Linux", IAS_KERNEL_ATTR); - - oct_seq[0] = 0x01; /* Version 1 */ - oct_seq[1] = 0x00; /* IAS support bits */ - oct_seq[2] = 0x00; /* LM-MUX support bits */ -#ifdef CONFIG_IRDA_ULTRA - oct_seq[2] |= 0x04; /* Connectionless Data support */ -#endif - irias_add_octseq_attrib(obj, "IrLMPSupport", oct_seq, 3, - IAS_KERNEL_ATTR); - irias_insert_object(obj); - - /* - * Register server support with IrLMP so we can accept incoming - * connections - */ - server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); - if (!server) { - pr_debug("%s(), unable to open server\n", __func__); - return -1; - } - iriap_register_lsap(server, LSAP_IAS, IAS_SERVER); - - return 0; -} - -/* - * Function iriap_cleanup (void) - * - * Initializes the IrIAP layer, called by the module cleanup code in - * irmod.c - */ -void iriap_cleanup(void) -{ - irlmp_unregister_service(service_handle); - - hashbin_delete(iriap, (FREE_FUNC) __iriap_close); - hashbin_delete(irias_objects, (FREE_FUNC) __irias_delete_object); -} - -/* - * Function iriap_open (void) - * - * Opens an instance of the IrIAP layer, and registers with IrLMP - */ -struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, - CONFIRM_CALLBACK callback) -{ - struct iriap_cb *self; - - self = kzalloc(sizeof(*self), GFP_ATOMIC); - if (!self) - return NULL; - - /* - * Initialize instance - */ - - self->magic = IAS_MAGIC; - self->mode = mode; - if (mode == IAS_CLIENT) { - if (iriap_register_lsap(self, slsap_sel, mode)) { - kfree(self); - return NULL; - } - } - - self->confirm = callback; - self->priv = priv; - - /* iriap_getvaluebyclass_request() will construct packets before - * we connect, so this must have a sane value... Jean II */ - self->max_header_size = LMP_MAX_HEADER; - - timer_setup(&self->watchdog_timer, NULL, 0); - - hashbin_insert(iriap, (irda_queue_t *) self, (long) self, NULL); - - /* Initialize state machines */ - iriap_next_client_state(self, S_DISCONNECT); - iriap_next_call_state(self, S_MAKE_CALL); - iriap_next_server_state(self, R_DISCONNECT); - iriap_next_r_connect_state(self, R_WAITING); - - return self; -} -EXPORT_SYMBOL(iriap_open); - -/* - * Function __iriap_close (self) - * - * Removes (deallocates) the IrIAP instance - * - */ -static void __iriap_close(struct iriap_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - del_timer(&self->watchdog_timer); - - if (self->request_skb) - dev_kfree_skb(self->request_skb); - - self->magic = 0; - - kfree(self); -} - -/* - * Function iriap_close (void) - * - * Closes IrIAP and deregisters with IrLMP - */ -void iriap_close(struct iriap_cb *self) -{ - struct iriap_cb *entry; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - if (self->lsap) { - irlmp_close_lsap(self->lsap); - self->lsap = NULL; - } - - entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL); - IRDA_ASSERT(entry == self, return;); - - __iriap_close(self); -} -EXPORT_SYMBOL(iriap_close); - -static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) -{ - notify_t notify; - - irda_notify_init(¬ify); - notify.connect_confirm = iriap_connect_confirm; - notify.connect_indication = iriap_connect_indication; - notify.disconnect_indication = iriap_disconnect_indication; - notify.data_indication = iriap_data_indication; - notify.instance = self; - if (mode == IAS_CLIENT) - strcpy(notify.name, "IrIAS cli"); - else - strcpy(notify.name, "IrIAS srv"); - - self->lsap = irlmp_open_lsap(slsap_sel, ¬ify, 0); - if (self->lsap == NULL) { - net_err_ratelimited("%s: Unable to allocated LSAP!\n", - __func__); - return -1; - } - self->slsap_sel = self->lsap->slsap_sel; - - return 0; -} - -/* - * Function iriap_disconnect_indication (handle, reason) - * - * Got disconnect, so clean up everything associated with this connection - * - */ -static void iriap_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *skb) -{ - struct iriap_cb *self; - - pr_debug("%s(), reason=%s [%d]\n", __func__, - irlmp_reason_str(reason), reason); - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - IRDA_ASSERT(iriap != NULL, return;); - - del_timer(&self->watchdog_timer); - - /* Not needed */ - if (skb) - dev_kfree_skb(skb); - - if (self->mode == IAS_CLIENT) { - pr_debug("%s(), disconnect as client\n", __func__); - - - iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION, - NULL); - /* - * Inform service user that the request failed by sending - * it a NULL value. Warning, the client might close us, so - * remember no to use self anymore after calling confirm - */ - if (self->confirm) - self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); - } else { - pr_debug("%s(), disconnect as server\n", __func__); - iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, - NULL); - iriap_close(self); - } -} - -/* - * Function iriap_disconnect_request (handle) - */ -static void iriap_disconnect_request(struct iriap_cb *self) -{ - struct sk_buff *tx_skb; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); - if (tx_skb == NULL) { - pr_debug("%s(), Could not allocate an sk_buff of length %d\n", - __func__, LMP_MAX_HEADER); - return; - } - - /* - * Reserve space for MUX control and LAP header - */ - skb_reserve(tx_skb, LMP_MAX_HEADER); - - irlmp_disconnect_request(self->lsap, tx_skb); -} - -/* - * Function iriap_getvaluebyclass (addr, name, attr) - * - * Retrieve all values from attribute in all objects with given class - * name - */ -int iriap_getvaluebyclass_request(struct iriap_cb *self, - __u32 saddr, __u32 daddr, - char *name, char *attr) -{ - struct sk_buff *tx_skb; - int name_len, attr_len, skb_len; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return -1;); - - /* Client must supply the destination device address */ - if (!daddr) - return -1; - - self->daddr = daddr; - self->saddr = saddr; - - /* - * Save operation, so we know what the later indication is about - */ - self->operation = GET_VALUE_BY_CLASS; - - /* Give ourselves 10 secs to finish this operation */ - iriap_start_watchdog_timer(self, 10*HZ); - - name_len = strlen(name); /* Up to IAS_MAX_CLASSNAME = 60 */ - attr_len = strlen(attr); /* Up to IAS_MAX_ATTRIBNAME = 60 */ - - skb_len = self->max_header_size+2+name_len+1+attr_len+4; - tx_skb = alloc_skb(skb_len, GFP_ATOMIC); - if (!tx_skb) - return -ENOMEM; - - /* Reserve space for MUX and LAP header */ - skb_reserve(tx_skb, self->max_header_size); - skb_put(tx_skb, 3+name_len+attr_len); - frame = tx_skb->data; - - /* Build frame */ - frame[0] = IAP_LST | GET_VALUE_BY_CLASS; - frame[1] = name_len; /* Insert length of name */ - memcpy(frame+2, name, name_len); /* Insert name */ - frame[2+name_len] = attr_len; /* Insert length of attr */ - memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */ - - iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, tx_skb); - - /* Drop reference count - see state_s_disconnect(). */ - dev_kfree_skb(tx_skb); - - return 0; -} -EXPORT_SYMBOL(iriap_getvaluebyclass_request); - -/* - * Function iriap_getvaluebyclass_confirm (self, skb) - * - * Got result from GetValueByClass command. Parse it and return result - * to service user. - * - */ -static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, - struct sk_buff *skb) -{ - struct ias_value *value; - int charset; - __u32 value_len; - __u32 tmp_cpu32; - __u16 obj_id; - __u16 len; - __u8 type; - __u8 *fp; - int n; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - /* Initialize variables */ - fp = skb->data; - n = 2; - - /* Get length, MSB first */ - len = get_unaligned_be16(fp + n); - n += 2; - - pr_debug("%s(), len=%d\n", __func__, len); - - /* Get object ID, MSB first */ - obj_id = get_unaligned_be16(fp + n); - n += 2; - - type = fp[n++]; - pr_debug("%s(), Value type = %d\n", __func__, type); - - switch (type) { - case IAS_INTEGER: - memcpy(&tmp_cpu32, fp+n, 4); n += 4; - be32_to_cpus(&tmp_cpu32); - value = irias_new_integer_value(tmp_cpu32); - - /* Legal values restricted to 0x01-0x6f, page 15 irttp */ - pr_debug("%s(), lsap=%d\n", __func__, value->t.integer); - break; - case IAS_STRING: - charset = fp[n++]; - - switch (charset) { - case CS_ASCII: - break; -/* case CS_ISO_8859_1: */ -/* case CS_ISO_8859_2: */ -/* case CS_ISO_8859_3: */ -/* case CS_ISO_8859_4: */ -/* case CS_ISO_8859_5: */ -/* case CS_ISO_8859_6: */ -/* case CS_ISO_8859_7: */ -/* case CS_ISO_8859_8: */ -/* case CS_ISO_8859_9: */ -/* case CS_UNICODE: */ - default: - pr_debug("%s(), charset [%d] %s, not supported\n", - __func__, charset, - charset < ARRAY_SIZE(ias_charset_types) ? - ias_charset_types[charset] : - "(unknown)"); - - /* Aborting, close connection! */ - iriap_disconnect_request(self); - return; - /* break; */ - } - value_len = fp[n++]; - pr_debug("%s(), strlen=%d\n", __func__, value_len); - - /* Make sure the string is null-terminated */ - if (n + value_len < skb->len) - fp[n + value_len] = 0x00; - pr_debug("Got string %s\n", fp+n); - - /* Will truncate to IAS_MAX_STRING bytes */ - value = irias_new_string_value(fp+n); - break; - case IAS_OCT_SEQ: - value_len = get_unaligned_be16(fp + n); - n += 2; - - /* Will truncate to IAS_MAX_OCTET_STRING bytes */ - value = irias_new_octseq_value(fp+n, value_len); - break; - default: - value = irias_new_missing_value(); - break; - } - - /* Finished, close connection! */ - iriap_disconnect_request(self); - - /* Warning, the client might close us, so remember no to use self - * anymore after calling confirm - */ - if (self->confirm) - self->confirm(IAS_SUCCESS, obj_id, value, self->priv); - else { - pr_debug("%s(), missing handler!\n", __func__); - irias_delete_value(value); - } -} - -/* - * Function iriap_getvaluebyclass_response () - * - * Send answer back to remote LM-IAS - * - */ -static void iriap_getvaluebyclass_response(struct iriap_cb *self, - __u16 obj_id, - __u8 ret_code, - struct ias_value *value) -{ - struct sk_buff *tx_skb; - int n; - __be32 tmp_be32; - __be16 tmp_be16; - __u8 *fp; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - IRDA_ASSERT(value != NULL, return;); - IRDA_ASSERT(value->len <= 1024, return;); - - /* Initialize variables */ - n = 0; - - /* - * We must adjust the size of the response after the length of the - * value. We add 32 bytes because of the 6 bytes for the frame and - * max 5 bytes for the value coding. - */ - tx_skb = alloc_skb(value->len + self->max_header_size + 32, - GFP_ATOMIC); - if (!tx_skb) - return; - - /* Reserve space for MUX and LAP header */ - skb_reserve(tx_skb, self->max_header_size); - skb_put(tx_skb, 6); - - fp = tx_skb->data; - - /* Build frame */ - fp[n++] = GET_VALUE_BY_CLASS | IAP_LST; - fp[n++] = ret_code; - - /* Insert list length (MSB first) */ - tmp_be16 = htons(0x0001); - memcpy(fp+n, &tmp_be16, 2); n += 2; - - /* Insert object identifier ( MSB first) */ - tmp_be16 = cpu_to_be16(obj_id); - memcpy(fp+n, &tmp_be16, 2); n += 2; - - switch (value->type) { - case IAS_STRING: - skb_put(tx_skb, 3 + value->len); - fp[n++] = value->type; - fp[n++] = 0; /* ASCII */ - fp[n++] = (__u8) value->len; - memcpy(fp+n, value->t.string, value->len); n+=value->len; - break; - case IAS_INTEGER: - skb_put(tx_skb, 5); - fp[n++] = value->type; - - tmp_be32 = cpu_to_be32(value->t.integer); - memcpy(fp+n, &tmp_be32, 4); n += 4; - break; - case IAS_OCT_SEQ: - skb_put(tx_skb, 3 + value->len); - fp[n++] = value->type; - - tmp_be16 = cpu_to_be16(value->len); - memcpy(fp+n, &tmp_be16, 2); n += 2; - memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len; - break; - case IAS_MISSING: - pr_debug("%s: sending IAS_MISSING\n", __func__); - skb_put(tx_skb, 1); - fp[n++] = value->type; - break; - default: - pr_debug("%s(), type not implemented!\n", __func__); - break; - } - iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb); - - /* Drop reference count - see state_r_execute(). */ - dev_kfree_skb(tx_skb); -} - -/* - * Function iriap_getvaluebyclass_indication (self, skb) - * - * getvaluebyclass is requested from peer LM-IAS - * - */ -static void iriap_getvaluebyclass_indication(struct iriap_cb *self, - struct sk_buff *skb) -{ - struct ias_object *obj; - struct ias_attrib *attrib; - int name_len; - int attr_len; - char name[IAS_MAX_CLASSNAME + 1]; /* 60 bytes */ - char attr[IAS_MAX_ATTRIBNAME + 1]; /* 60 bytes */ - __u8 *fp; - int n; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - fp = skb->data; - n = 1; - - name_len = fp[n++]; - - IRDA_ASSERT(name_len < IAS_MAX_CLASSNAME + 1, return;); - - memcpy(name, fp+n, name_len); n+=name_len; - name[name_len] = '\0'; - - attr_len = fp[n++]; - - IRDA_ASSERT(attr_len < IAS_MAX_ATTRIBNAME + 1, return;); - - memcpy(attr, fp+n, attr_len); n+=attr_len; - attr[attr_len] = '\0'; - - pr_debug("LM-IAS: Looking up %s: %s\n", name, attr); - obj = irias_find_object(name); - - if (obj == NULL) { - pr_debug("LM-IAS: Object %s not found\n", name); - iriap_getvaluebyclass_response(self, 0x1235, IAS_CLASS_UNKNOWN, - &irias_missing); - return; - } - pr_debug("LM-IAS: found %s, id=%d\n", obj->name, obj->id); - - attrib = irias_find_attrib(obj, attr); - if (attrib == NULL) { - pr_debug("LM-IAS: Attribute %s not found\n", attr); - iriap_getvaluebyclass_response(self, obj->id, - IAS_ATTRIB_UNKNOWN, - &irias_missing); - return; - } - - /* We have a match; send the value. */ - iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS, - attrib->value); -} - -/* - * Function iriap_send_ack (void) - * - * Currently not used - * - */ -void iriap_send_ack(struct iriap_cb *self) -{ - struct sk_buff *tx_skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC); - if (!tx_skb) - return; - - /* Reserve space for MUX and LAP header */ - skb_reserve(tx_skb, self->max_header_size); - skb_put(tx_skb, 1); - frame = tx_skb->data; - - /* Build frame */ - frame[0] = IAP_LST | IAP_ACK | self->operation; - - irlmp_data_request(self->lsap, tx_skb); -} - -void iriap_connect_request(struct iriap_cb *self) -{ - int ret; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - ret = irlmp_connect_request(self->lsap, LSAP_IAS, - self->saddr, self->daddr, - NULL, NULL); - if (ret < 0) { - pr_debug("%s(), connect failed!\n", __func__); - self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); - } -} - -/* - * Function iriap_connect_confirm (handle, skb) - * - * LSAP connection confirmed! - * - */ -static void iriap_connect_confirm(void *instance, void *sap, - struct qos_info *qos, __u32 max_seg_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct iriap_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - self->max_data_size = max_seg_size; - self->max_header_size = max_header_size; - - del_timer(&self->watchdog_timer); - - iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, skb); - - /* Drop reference count - see state_s_make_call(). */ - dev_kfree_skb(skb); -} - -/* - * Function iriap_connect_indication ( handle, skb) - * - * Remote LM-IAS is requesting connection - * - */ -static void iriap_connect_indication(void *instance, void *sap, - struct qos_info *qos, __u32 max_seg_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct iriap_cb *self, *new; - - self = instance; - - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(self != NULL, goto out;); - IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); - - /* Start new server */ - new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); - if (!new) { - pr_debug("%s(), open failed\n", __func__); - goto out; - } - - /* Now attach up the new "socket" */ - new->lsap = irlmp_dup(self->lsap, new); - if (!new->lsap) { - pr_debug("%s(), dup failed!\n", __func__); - goto out; - } - - new->max_data_size = max_seg_size; - new->max_header_size = max_header_size; - - /* Clean up the original one to keep it in listen state */ - irlmp_listen(self->lsap); - - iriap_do_server_event(new, IAP_LM_CONNECT_INDICATION, skb); - -out: - /* Drop reference count - see state_r_disconnect(). */ - dev_kfree_skb(skb); -} - -/* - * Function iriap_data_indication (handle, skb) - * - * Receives data from connection identified by handle from IrLMP - * - */ -static int iriap_data_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct iriap_cb *self; - __u8 *frame; - __u8 opcode; - - self = instance; - - IRDA_ASSERT(skb != NULL, return 0;); - IRDA_ASSERT(self != NULL, goto out;); - IRDA_ASSERT(self->magic == IAS_MAGIC, goto out;); - - frame = skb->data; - - if (self->mode == IAS_SERVER) { - /* Call server */ - pr_debug("%s(), Calling server!\n", __func__); - iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); - goto out; - } - opcode = frame[0]; - if (~opcode & IAP_LST) { - net_warn_ratelimited("%s:, IrIAS multiframe commands or results is not implemented yet!\n", - __func__); - goto out; - } - - /* Check for ack frames since they don't contain any data */ - if (opcode & IAP_ACK) { - pr_debug("%s() Got ack frame!\n", __func__); - goto out; - } - - opcode &= ~IAP_LST; /* Mask away LST bit */ - - switch (opcode) { - case GET_INFO_BASE: - pr_debug("IrLMP GetInfoBaseDetails not implemented!\n"); - break; - case GET_VALUE_BY_CLASS: - iriap_do_call_event(self, IAP_RECV_F_LST, NULL); - - switch (frame[1]) { - case IAS_SUCCESS: - iriap_getvaluebyclass_confirm(self, skb); - break; - case IAS_CLASS_UNKNOWN: - pr_debug("%s(), No such class!\n", __func__); - /* Finished, close connection! */ - iriap_disconnect_request(self); - - /* - * Warning, the client might close us, so remember - * no to use self anymore after calling confirm - */ - if (self->confirm) - self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, - self->priv); - break; - case IAS_ATTRIB_UNKNOWN: - pr_debug("%s(), No such attribute!\n", __func__); - /* Finished, close connection! */ - iriap_disconnect_request(self); - - /* - * Warning, the client might close us, so remember - * no to use self anymore after calling confirm - */ - if (self->confirm) - self->confirm(IAS_ATTRIB_UNKNOWN, 0, NULL, - self->priv); - break; - } - break; - default: - pr_debug("%s(), Unknown op-code: %02x\n", __func__, - opcode); - break; - } - -out: - /* Cleanup - sub-calls will have done skb_get() as needed. */ - dev_kfree_skb(skb); - return 0; -} - -/* - * Function iriap_call_indication (self, skb) - * - * Received call to server from peer LM-IAS - * - */ -void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) -{ - __u8 *fp; - __u8 opcode; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - fp = skb->data; - - opcode = fp[0]; - if (~opcode & 0x80) { - net_warn_ratelimited("%s: IrIAS multiframe commands or results is not implemented yet!\n", - __func__); - return; - } - opcode &= 0x7f; /* Mask away LST bit */ - - switch (opcode) { - case GET_INFO_BASE: - net_warn_ratelimited("%s: GetInfoBaseDetails not implemented yet!\n", - __func__); - break; - case GET_VALUE_BY_CLASS: - iriap_getvaluebyclass_indication(self, skb); - break; - } - /* skb will be cleaned up in iriap_data_indication */ -} - -/* - * Function iriap_watchdog_timer_expired (data) - * - * Query has taken too long time, so abort - * - */ -static void iriap_watchdog_timer_expired(struct timer_list *t) -{ - struct iriap_cb *self = from_timer(self, t, watchdog_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - /* iriap_close(self); */ -} - -#ifdef CONFIG_PROC_FS - -static const char *const ias_value_types[] = { - "IAS_MISSING", - "IAS_INTEGER", - "IAS_OCT_SEQ", - "IAS_STRING" -}; - -static inline struct ias_object *irias_seq_idx(loff_t pos) -{ - struct ias_object *obj; - - for (obj = (struct ias_object *) hashbin_get_first(irias_objects); - obj; obj = (struct ias_object *) hashbin_get_next(irias_objects)) { - if (pos-- == 0) - break; - } - - return obj; -} - -static void *irias_seq_start(struct seq_file *seq, loff_t *pos) -{ - spin_lock_irq(&irias_objects->hb_spinlock); - - return *pos ? irias_seq_idx(*pos - 1) : SEQ_START_TOKEN; -} - -static void *irias_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - - return (v == SEQ_START_TOKEN) - ? (void *) hashbin_get_first(irias_objects) - : (void *) hashbin_get_next(irias_objects); -} - -static void irias_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_irq(&irias_objects->hb_spinlock); -} - -static int irias_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_puts(seq, "LM-IAS Objects:\n"); - else { - struct ias_object *obj = v; - struct ias_attrib *attrib; - - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -EINVAL;); - - seq_printf(seq, "name: %s, id=%d\n", - obj->name, obj->id); - - /* Careful for priority inversions here ! - * All other uses of attrib spinlock are independent of - * the object spinlock, so we are safe. Jean II */ - spin_lock(&obj->attribs->hb_spinlock); - - /* List all attributes for this object */ - for (attrib = (struct ias_attrib *) hashbin_get_first(obj->attribs); - attrib != NULL; - attrib = (struct ias_attrib *) hashbin_get_next(obj->attribs)) { - - IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, - goto outloop; ); - - seq_printf(seq, " - Attribute name: \"%s\", ", - attrib->name); - seq_printf(seq, "value[%s]: ", - ias_value_types[attrib->value->type]); - - switch (attrib->value->type) { - case IAS_INTEGER: - seq_printf(seq, "%d\n", - attrib->value->t.integer); - break; - case IAS_STRING: - seq_printf(seq, "\"%s\"\n", - attrib->value->t.string); - break; - case IAS_OCT_SEQ: - seq_printf(seq, "octet sequence (%d bytes)\n", - attrib->value->len); - break; - case IAS_MISSING: - seq_puts(seq, "missing\n"); - break; - default: - seq_printf(seq, "type %d?\n", - attrib->value->type); - } - seq_putc(seq, '\n'); - - } - IRDA_ASSERT_LABEL(outloop:) - spin_unlock(&obj->attribs->hb_spinlock); - } - - return 0; -} - -static const struct seq_operations irias_seq_ops = { - .start = irias_seq_start, - .next = irias_seq_next, - .stop = irias_seq_stop, - .show = irias_seq_show, -}; - -static int irias_seq_open(struct inode *inode, struct file *file) -{ - IRDA_ASSERT( irias_objects != NULL, return -EINVAL;); - - return seq_open(file, &irias_seq_ops); -} - -const struct file_operations irias_seq_fops = { - .owner = THIS_MODULE, - .open = irias_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -#endif /* PROC_FS */ diff --git a/drivers/staging/irda/net/iriap_event.c b/drivers/staging/irda/net/iriap_event.c deleted file mode 100644 index e6098b2e048a..000000000000 --- a/drivers/staging/irda/net/iriap_event.c +++ /dev/null @@ -1,496 +0,0 @@ -/********************************************************************* - * - * Filename: iriap_event.c - * Version: 0.1 - * Description: IAP Finite State Machine - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Aug 21 00:02:07 1997 - * Modified at: Wed Mar 1 11:28:34 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/slab.h> - -#include <net/irda/irda.h> -#include <net/irda/irlmp.h> -#include <net/irda/iriap.h> -#include <net/irda/iriap_event.h> - -static void state_s_disconnect (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_s_connecting (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_s_call (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); - -static void state_s_make_call (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_s_calling (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_s_outstanding (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_s_replying (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_s_wait_active (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); - -static void state_r_disconnect (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_r_call (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_r_waiting (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_r_wait_active (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_r_receiving (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_r_execute (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); -static void state_r_returning (struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb); - -static void (*iriap_state[])(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) = { - /* Client FSM */ - state_s_disconnect, - state_s_connecting, - state_s_call, - - /* S-Call FSM */ - state_s_make_call, - state_s_calling, - state_s_outstanding, - state_s_replying, - state_s_wait_for_call, - state_s_wait_active, - - /* Server FSM */ - state_r_disconnect, - state_r_call, - - /* R-Connect FSM */ - state_r_waiting, - state_r_wait_active, - state_r_receiving, - state_r_execute, - state_r_returning, -}; - -void iriap_next_client_state(struct iriap_cb *self, IRIAP_STATE state) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - self->client_state = state; -} - -void iriap_next_call_state(struct iriap_cb *self, IRIAP_STATE state) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - self->call_state = state; -} - -void iriap_next_server_state(struct iriap_cb *self, IRIAP_STATE state) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - self->server_state = state; -} - -void iriap_next_r_connect_state(struct iriap_cb *self, IRIAP_STATE state) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - self->r_connect_state = state; -} - -void iriap_do_client_event(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - (*iriap_state[ self->client_state]) (self, event, skb); -} - -void iriap_do_call_event(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - (*iriap_state[ self->call_state]) (self, event, skb); -} - -void iriap_do_server_event(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - (*iriap_state[ self->server_state]) (self, event, skb); -} - -void iriap_do_r_connect_event(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - (*iriap_state[ self->r_connect_state]) (self, event, skb); -} - - -/* - * Function state_s_disconnect (event, skb) - * - * S-Disconnect, The device has no LSAP connection to a particular - * remote device. - */ -static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - switch (event) { - case IAP_CALL_REQUEST_GVBC: - iriap_next_client_state(self, S_CONNECTING); - IRDA_ASSERT(self->request_skb == NULL, return;); - /* Don't forget to refcount it - - * see iriap_getvaluebyclass_request(). */ - skb_get(skb); - self->request_skb = skb; - iriap_connect_request(self); - break; - case IAP_LM_DISCONNECT_INDICATION: - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__, event); - break; - } -} - -/* - * Function state_s_connecting (self, event, skb) - * - * S-Connecting - * - */ -static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - switch (event) { - case IAP_LM_CONNECT_CONFIRM: - /* - * Jump to S-Call FSM - */ - iriap_do_call_event(self, IAP_CALL_REQUEST, skb); - /* iriap_call_request(self, 0,0,0); */ - iriap_next_client_state(self, S_CALL); - break; - case IAP_LM_DISCONNECT_INDICATION: - /* Abort calls */ - iriap_next_call_state(self, S_MAKE_CALL); - iriap_next_client_state(self, S_DISCONNECT); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__, event); - break; - } -} - -/* - * Function state_s_call (self, event, skb) - * - * S-Call, The device can process calls to a specific remote - * device. Whenever the LSAP connection is disconnected, this state - * catches that event and clears up - */ -static void state_s_call(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - - switch (event) { - case IAP_LM_DISCONNECT_INDICATION: - /* Abort calls */ - iriap_next_call_state(self, S_MAKE_CALL); - iriap_next_client_state(self, S_DISCONNECT); - break; - default: - pr_debug("state_s_call: Unknown event %d\n", event); - break; - } -} - -/* - * Function state_s_make_call (event, skb) - * - * S-Make-Call - * - */ -static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - struct sk_buff *tx_skb; - - IRDA_ASSERT(self != NULL, return;); - - switch (event) { - case IAP_CALL_REQUEST: - /* Already refcounted - see state_s_disconnect() */ - tx_skb = self->request_skb; - self->request_skb = NULL; - - irlmp_data_request(self->lsap, tx_skb); - iriap_next_call_state(self, S_OUTSTANDING); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__, event); - break; - } -} - -/* - * Function state_s_calling (event, skb) - * - * S-Calling - * - */ -static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), Not implemented\n", __func__); -} - -/* - * Function state_s_outstanding (event, skb) - * - * S-Outstanding, The device is waiting for a response to a command - * - */ -static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - - switch (event) { - case IAP_RECV_F_LST: - /*iriap_send_ack(self);*/ - /*LM_Idle_request(idle); */ - - iriap_next_call_state(self, S_WAIT_FOR_CALL); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__, event); - break; - } -} - -/* - * Function state_s_replying (event, skb) - * - * S-Replying, The device is collecting a multiple part response - */ -static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), Not implemented\n", __func__); -} - -/* - * Function state_s_wait_for_call (event, skb) - * - * S-Wait-for-Call - * - */ -static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), Not implemented\n", __func__); -} - - -/* - * Function state_s_wait_active (event, skb) - * - * S-Wait-Active - * - */ -static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), Not implemented\n", __func__); -} - -/************************************************************************** - * - * Server FSM - * - **************************************************************************/ - -/* - * Function state_r_disconnect (self, event, skb) - * - * LM-IAS server is disconnected (not processing any requests!) - * - */ -static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - struct sk_buff *tx_skb; - - switch (event) { - case IAP_LM_CONNECT_INDICATION: - tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); - if (tx_skb == NULL) - return; - - /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve(tx_skb, LMP_MAX_HEADER); - - irlmp_connect_response(self->lsap, tx_skb); - /*LM_Idle_request(idle); */ - - iriap_next_server_state(self, R_CALL); - - /* - * Jump to R-Connect FSM, we skip R-Waiting since we do not - * care about LM_Idle_request()! - */ - iriap_next_r_connect_state(self, R_RECEIVING); - break; - default: - pr_debug("%s(), unknown event %d\n", __func__, event); - break; - } -} - -/* - * Function state_r_call (self, event, skb) - */ -static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - switch (event) { - case IAP_LM_DISCONNECT_INDICATION: - /* Abort call */ - iriap_next_server_state(self, R_DISCONNECT); - iriap_next_r_connect_state(self, R_WAITING); - break; - default: - pr_debug("%s(), unknown event!\n", __func__); - break; - } -} - -/* - * R-Connect FSM - */ - -/* - * Function state_r_waiting (self, event, skb) - */ -static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), Not implemented\n", __func__); -} - -static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), Not implemented\n", __func__); -} - -/* - * Function state_r_receiving (self, event, skb) - * - * We are receiving a command - * - */ -static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - switch (event) { - case IAP_RECV_F_LST: - iriap_next_r_connect_state(self, R_EXECUTE); - - iriap_call_indication(self, skb); - break; - default: - pr_debug("%s(), unknown event!\n", __func__); - break; - } -} - -/* - * Function state_r_execute (self, event, skb) - * - * The server is processing the request - * - */ -static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IAS_MAGIC, return;); - - switch (event) { - case IAP_CALL_RESPONSE: - /* - * Since we don't implement the Waiting state, we return - * to state Receiving instead, DB. - */ - iriap_next_r_connect_state(self, R_RECEIVING); - - /* Don't forget to refcount it - see - * iriap_getvaluebyclass_response(). */ - skb_get(skb); - - irlmp_data_request(self->lsap, skb); - break; - default: - pr_debug("%s(), unknown event!\n", __func__); - break; - } -} - -static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), event=%d\n", __func__, event); - - switch (event) { - case IAP_RECV_F_LST: - break; - default: - break; - } -} diff --git a/drivers/staging/irda/net/irias_object.c b/drivers/staging/irda/net/irias_object.c deleted file mode 100644 index 53b86d0e1630..000000000000 --- a/drivers/staging/irda/net/irias_object.c +++ /dev/null @@ -1,555 +0,0 @@ -/********************************************************************* - * - * Filename: irias_object.c - * Version: 0.3 - * Description: IAS object database and functions - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Oct 1 22:50:04 1998 - * Modified at: Wed Dec 15 11:23:16 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/socket.h> -#include <linux/module.h> - -#include <net/irda/irda.h> -#include <net/irda/irias_object.h> - -hashbin_t *irias_objects; - -/* - * Used when a missing value needs to be returned - */ -struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}}; - - -/* - * Function ias_new_object (name, id) - * - * Create a new IAS object - * - */ -struct ias_object *irias_new_object( char *name, int id) -{ - struct ias_object *obj; - - obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC); - if (obj == NULL) { - net_warn_ratelimited("%s(), Unable to allocate object!\n", - __func__); - return NULL; - } - - obj->magic = IAS_OBJECT_MAGIC; - obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC); - if (!obj->name) { - net_warn_ratelimited("%s(), Unable to allocate name!\n", - __func__); - kfree(obj); - return NULL; - } - obj->id = id; - - /* Locking notes : the attrib spinlock has lower precendence - * than the objects spinlock. Never grap the objects spinlock - * while holding any attrib spinlock (risk of deadlock). Jean II */ - obj->attribs = hashbin_new(HB_LOCK); - - if (obj->attribs == NULL) { - net_warn_ratelimited("%s(), Unable to allocate attribs!\n", - __func__); - kfree(obj->name); - kfree(obj); - return NULL; - } - - return obj; -} -EXPORT_SYMBOL(irias_new_object); - -/* - * Function irias_delete_attrib (attrib) - * - * Delete given attribute and deallocate all its memory - * - */ -static void __irias_delete_attrib(struct ias_attrib *attrib) -{ - IRDA_ASSERT(attrib != NULL, return;); - IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); - - kfree(attrib->name); - - irias_delete_value(attrib->value); - attrib->magic = ~IAS_ATTRIB_MAGIC; - - kfree(attrib); -} - -void __irias_delete_object(struct ias_object *obj) -{ - IRDA_ASSERT(obj != NULL, return;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - - kfree(obj->name); - - hashbin_delete(obj->attribs, (FREE_FUNC) __irias_delete_attrib); - - obj->magic = ~IAS_OBJECT_MAGIC; - - kfree(obj); -} - -/* - * Function irias_delete_object (obj) - * - * Remove object from hashbin and deallocate all attributes associated with - * with this object and the object itself - * - */ -int irias_delete_object(struct ias_object *obj) -{ - struct ias_object *node; - - IRDA_ASSERT(obj != NULL, return -1;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); - - /* Remove from list */ - node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj); - if (!node) - pr_debug("%s(), object already removed!\n", - __func__); - - /* Destroy */ - __irias_delete_object(obj); - - return 0; -} -EXPORT_SYMBOL(irias_delete_object); - -/* - * Function irias_delete_attrib (obj) - * - * Remove attribute from hashbin and, if it was the last attribute of - * the object, remove the object as well. - * - */ -int irias_delete_attrib(struct ias_object *obj, struct ias_attrib *attrib, - int cleanobject) -{ - struct ias_attrib *node; - - IRDA_ASSERT(obj != NULL, return -1;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;); - IRDA_ASSERT(attrib != NULL, return -1;); - - /* Remove attribute from object */ - node = hashbin_remove_this(obj->attribs, (irda_queue_t *) attrib); - if (!node) - return 0; /* Already removed or non-existent */ - - /* Deallocate attribute */ - __irias_delete_attrib(node); - - /* Check if object has still some attributes, destroy it if none. - * At first glance, this look dangerous, as the kernel reference - * various IAS objects. However, we only use this function on - * user attributes, not kernel attributes, so there is no risk - * of deleting a kernel object this way. Jean II */ - node = (struct ias_attrib *) hashbin_get_first(obj->attribs); - if (cleanobject && !node) - irias_delete_object(obj); - - return 0; -} - -/* - * Function irias_insert_object (obj) - * - * Insert an object into the LM-IAS database - * - */ -void irias_insert_object(struct ias_object *obj) -{ - IRDA_ASSERT(obj != NULL, return;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - - hashbin_insert(irias_objects, (irda_queue_t *) obj, 0, obj->name); -} -EXPORT_SYMBOL(irias_insert_object); - -/* - * Function irias_find_object (name) - * - * Find object with given name - * - */ -struct ias_object *irias_find_object(char *name) -{ - IRDA_ASSERT(name != NULL, return NULL;); - - /* Unsafe (locking), object might change */ - return hashbin_lock_find(irias_objects, 0, name); -} -EXPORT_SYMBOL(irias_find_object); - -/* - * Function irias_find_attrib (obj, name) - * - * Find named attribute in object - * - */ -struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name) -{ - struct ias_attrib *attrib; - - IRDA_ASSERT(obj != NULL, return NULL;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;); - IRDA_ASSERT(name != NULL, return NULL;); - - attrib = hashbin_lock_find(obj->attribs, 0, name); - if (attrib == NULL) - return NULL; - - /* Unsafe (locking), attrib might change */ - return attrib; -} - -/* - * Function irias_add_attribute (obj, attrib) - * - * Add attribute to object - * - */ -static void irias_add_attrib(struct ias_object *obj, struct ias_attrib *attrib, - int owner) -{ - IRDA_ASSERT(obj != NULL, return;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - - IRDA_ASSERT(attrib != NULL, return;); - IRDA_ASSERT(attrib->magic == IAS_ATTRIB_MAGIC, return;); - - /* Set if attrib is owned by kernel or user space */ - attrib->value->owner = owner; - - hashbin_insert(obj->attribs, (irda_queue_t *) attrib, 0, attrib->name); -} - -/* - * Function irias_object_change_attribute (obj_name, attrib_name, new_value) - * - * Change the value of an objects attribute. - * - */ -int irias_object_change_attribute(char *obj_name, char *attrib_name, - struct ias_value *new_value) -{ - struct ias_object *obj; - struct ias_attrib *attrib; - unsigned long flags; - - /* Find object */ - obj = hashbin_lock_find(irias_objects, 0, obj_name); - if (obj == NULL) { - net_warn_ratelimited("%s: Unable to find object: %s\n", - __func__, obj_name); - return -1; - } - - /* Slightly unsafe (obj might get removed under us) */ - spin_lock_irqsave(&obj->attribs->hb_spinlock, flags); - - /* Find attribute */ - attrib = hashbin_find(obj->attribs, 0, attrib_name); - if (attrib == NULL) { - net_warn_ratelimited("%s: Unable to find attribute: %s\n", - __func__, attrib_name); - spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); - return -1; - } - - if ( attrib->value->type != new_value->type) { - pr_debug("%s(), changing value type not allowed!\n", - __func__); - spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); - return -1; - } - - /* Delete old value */ - irias_delete_value(attrib->value); - - /* Insert new value */ - attrib->value = new_value; - - /* Success */ - spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); - return 0; -} -EXPORT_SYMBOL(irias_object_change_attribute); - -/* - * Function irias_object_add_integer_attrib (obj, name, value) - * - * Add an integer attribute to an LM-IAS object - * - */ -void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, - int owner) -{ - struct ias_attrib *attrib; - - IRDA_ASSERT(obj != NULL, return;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - IRDA_ASSERT(name != NULL, return;); - - attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); - if (attrib == NULL) { - net_warn_ratelimited("%s: Unable to allocate attribute!\n", - __func__); - return; - } - - attrib->magic = IAS_ATTRIB_MAGIC; - attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); - - /* Insert value */ - attrib->value = irias_new_integer_value(value); - if (!attrib->name || !attrib->value) { - net_warn_ratelimited("%s: Unable to allocate attribute!\n", - __func__); - if (attrib->value) - irias_delete_value(attrib->value); - kfree(attrib->name); - kfree(attrib); - return; - } - - irias_add_attrib(obj, attrib, owner); -} -EXPORT_SYMBOL(irias_add_integer_attrib); - - /* - * Function irias_add_octseq_attrib (obj, name, octet_seq, len) - * - * Add a octet sequence attribute to an LM-IAS object - * - */ - -void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, - int len, int owner) -{ - struct ias_attrib *attrib; - - IRDA_ASSERT(obj != NULL, return;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - - IRDA_ASSERT(name != NULL, return;); - IRDA_ASSERT(octets != NULL, return;); - - attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); - if (attrib == NULL) { - net_warn_ratelimited("%s: Unable to allocate attribute!\n", - __func__); - return; - } - - attrib->magic = IAS_ATTRIB_MAGIC; - attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); - - attrib->value = irias_new_octseq_value( octets, len); - if (!attrib->name || !attrib->value) { - net_warn_ratelimited("%s: Unable to allocate attribute!\n", - __func__); - if (attrib->value) - irias_delete_value(attrib->value); - kfree(attrib->name); - kfree(attrib); - return; - } - - irias_add_attrib(obj, attrib, owner); -} -EXPORT_SYMBOL(irias_add_octseq_attrib); - -/* - * Function irias_object_add_string_attrib (obj, string) - * - * Add a string attribute to an LM-IAS object - * - */ -void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, - int owner) -{ - struct ias_attrib *attrib; - - IRDA_ASSERT(obj != NULL, return;); - IRDA_ASSERT(obj->magic == IAS_OBJECT_MAGIC, return;); - - IRDA_ASSERT(name != NULL, return;); - IRDA_ASSERT(value != NULL, return;); - - attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC); - if (attrib == NULL) { - net_warn_ratelimited("%s: Unable to allocate attribute!\n", - __func__); - return; - } - - attrib->magic = IAS_ATTRIB_MAGIC; - attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC); - - attrib->value = irias_new_string_value(value); - if (!attrib->name || !attrib->value) { - net_warn_ratelimited("%s: Unable to allocate attribute!\n", - __func__); - if (attrib->value) - irias_delete_value(attrib->value); - kfree(attrib->name); - kfree(attrib); - return; - } - - irias_add_attrib(obj, attrib, owner); -} -EXPORT_SYMBOL(irias_add_string_attrib); - -/* - * Function irias_new_integer_value (integer) - * - * Create new IAS integer value - * - */ -struct ias_value *irias_new_integer_value(int integer) -{ - struct ias_value *value; - - value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); - if (value == NULL) - return NULL; - - value->type = IAS_INTEGER; - value->len = 4; - value->t.integer = integer; - - return value; -} -EXPORT_SYMBOL(irias_new_integer_value); - -/* - * Function irias_new_string_value (string) - * - * Create new IAS string value - * - * Per IrLMP 1.1, 4.3.3.2, strings are up to 256 chars - Jean II - */ -struct ias_value *irias_new_string_value(char *string) -{ - struct ias_value *value; - - value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); - if (value == NULL) - return NULL; - - value->type = IAS_STRING; - value->charset = CS_ASCII; - value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC); - if (!value->t.string) { - net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__); - kfree(value); - return NULL; - } - - value->len = strlen(value->t.string); - - return value; -} - -/* - * Function irias_new_octseq_value (octets, len) - * - * Create new IAS octet-sequence value - * - * Per IrLMP 1.1, 4.3.3.2, octet-sequence are up to 1024 bytes - Jean II - */ -struct ias_value *irias_new_octseq_value(__u8 *octseq , int len) -{ - struct ias_value *value; - - value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); - if (value == NULL) - return NULL; - - value->type = IAS_OCT_SEQ; - /* Check length */ - if(len > IAS_MAX_OCTET_STRING) - len = IAS_MAX_OCTET_STRING; - value->len = len; - - value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC); - if (value->t.oct_seq == NULL){ - net_warn_ratelimited("%s: Unable to kmalloc!\n", __func__); - kfree(value); - return NULL; - } - return value; -} - -struct ias_value *irias_new_missing_value(void) -{ - struct ias_value *value; - - value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); - if (value == NULL) - return NULL; - - value->type = IAS_MISSING; - - return value; -} - -/* - * Function irias_delete_value (value) - * - * Delete IAS value - * - */ -void irias_delete_value(struct ias_value *value) -{ - IRDA_ASSERT(value != NULL, return;); - - switch (value->type) { - case IAS_INTEGER: /* Fallthrough */ - case IAS_MISSING: - /* No need to deallocate */ - break; - case IAS_STRING: - /* Deallocate string */ - kfree(value->t.string); - break; - case IAS_OCT_SEQ: - /* Deallocate byte stream */ - kfree(value->t.oct_seq); - break; - default: - pr_debug("%s(), Unknown value type!\n", __func__); - break; - } - kfree(value); -} -EXPORT_SYMBOL(irias_delete_value); diff --git a/drivers/staging/irda/net/irlan/Kconfig b/drivers/staging/irda/net/irlan/Kconfig deleted file mode 100644 index 951abc2e3a7f..000000000000 --- a/drivers/staging/irda/net/irlan/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config IRLAN - tristate "IrLAN protocol" - depends on IRDA - help - Say Y here if you want to build support for the IrLAN protocol. - To compile it as a module, choose M here: the module will be called - irlan. IrLAN emulates an Ethernet and makes it possible to put up - a wireless LAN using infrared beams. - - The IrLAN protocol can be used to talk with infrared access points - like the HP NetbeamIR, or the ESI JetEye NET. You can also connect - to another Linux machine running the IrLAN protocol for ad-hoc - networking! - diff --git a/drivers/staging/irda/net/irlan/Makefile b/drivers/staging/irda/net/irlan/Makefile deleted file mode 100644 index 94eefbc8e6b9..000000000000 --- a/drivers/staging/irda/net/irlan/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the Linux IrDA IrLAN protocol layer. -# - -obj-$(CONFIG_IRLAN) += irlan.o - -irlan-y := irlan_common.o irlan_eth.o irlan_event.o irlan_client.o irlan_provider.o irlan_filter.o irlan_provider_event.o irlan_client_event.o diff --git a/drivers/staging/irda/net/irlan/irlan_client.c b/drivers/staging/irda/net/irlan/irlan_client.c deleted file mode 100644 index 0b65e80849ae..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_client.c +++ /dev/null @@ -1,559 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_client.c - * Version: 0.9 - * Description: IrDA LAN Access Protocol (IrLAN) Client - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Tue Dec 14 15:47:02 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> - * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> - * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if_arp.h> -#include <linux/bitops.h> -#include <net/arp.h> - -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/irttp.h> -#include <net/irda/irlmp.h> -#include <net/irda/irias_object.h> -#include <net/irda/iriap.h> -#include <net/irda/timer.h> - -#include <net/irda/irlan_common.h> -#include <net/irda/irlan_event.h> -#include <net/irda/irlan_eth.h> -#include <net/irda/irlan_provider.h> -#include <net/irda/irlan_client.h> - -#undef CONFIG_IRLAN_GRATUITOUS_ARP - -static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *); -static int irlan_client_ctrl_data_indication(void *instance, void *sap, - struct sk_buff *skb); -static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *); -static void irlan_check_response_param(struct irlan_cb *self, char *param, - char *value, int val_len); -static void irlan_client_open_ctrl_tsap(struct irlan_cb *self); - -static void irlan_client_kick_timer_expired(struct timer_list *t) -{ - struct irlan_cb *self = from_timer(self, t, client.kick_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* - * If we are in peer mode, the client may not have got the discovery - * indication it needs to make progress. If the client is still in - * IDLE state, we must kick it to, but only if the provider is not IDLE - */ - if ((self->provider.access_type == ACCESS_PEER) && - (self->client.state == IRLAN_IDLE) && - (self->provider.state != IRLAN_IDLE)) { - irlan_client_wakeup(self, self->saddr, self->daddr); - } -} - -static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout) -{ - irda_start_timer(&self->client.kick_timer, timeout, - irlan_client_kick_timer_expired); -} - -/* - * Function irlan_client_wakeup (self, saddr, daddr) - * - * Wake up client - * - */ -void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* - * Check if we are already awake, or if we are a provider in direct - * mode (in that case we must leave the client idle - */ - if ((self->client.state != IRLAN_IDLE) || - (self->provider.access_type == ACCESS_DIRECT)) - { - pr_debug("%s(), already awake!\n", __func__); - return; - } - - /* Addresses may have changed! */ - self->saddr = saddr; - self->daddr = daddr; - - if (self->disconnect_reason == LM_USER_REQUEST) { - pr_debug("%s(), still stopped by user\n", __func__); - return; - } - - /* Open TSAPs */ - irlan_client_open_ctrl_tsap(self); - irlan_open_data_tsap(self); - - irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL); - - /* Start kick timer */ - irlan_client_start_kick_timer(self, 2*HZ); -} - -/* - * Function irlan_discovery_indication (daddr) - * - * Remote device with IrLAN server support discovered - * - */ -void irlan_client_discovery_indication(discinfo_t *discovery, - DISCOVERY_MODE mode, - void *priv) -{ - struct irlan_cb *self; - __u32 saddr, daddr; - - IRDA_ASSERT(discovery != NULL, return;); - - /* - * I didn't check it, but I bet that IrLAN suffer from the same - * deficiency as IrComm and doesn't handle two instances - * simultaneously connecting to each other. - * Same workaround, drop passive discoveries. - * Jean II */ - if(mode == DISCOVERY_PASSIVE) - return; - - saddr = discovery->saddr; - daddr = discovery->daddr; - - /* Find instance */ - rcu_read_lock(); - self = irlan_get_any(); - if (self) { - IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;); - - pr_debug("%s(), Found instance (%08x)!\n", __func__ , - daddr); - - irlan_client_wakeup(self, saddr, daddr); - } -IRDA_ASSERT_LABEL(out:) - rcu_read_unlock(); -} - -/* - * Function irlan_client_data_indication (handle, skb) - * - * This function gets the data that is received on the control channel - * - */ -static int irlan_client_ctrl_data_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct irlan_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); - - /* Ready for a new command */ - pr_debug("%s(), clearing tx_busy\n", __func__); - self->client.tx_busy = FALSE; - - /* Check if we have some queued commands waiting to be sent */ - irlan_run_ctrl_tx_queue(self); - - return 0; -} - -static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *userdata) -{ - struct irlan_cb *self; - struct tsap_cb *tsap; - struct sk_buff *skb; - - pr_debug("%s(), reason=%d\n", __func__ , reason); - - self = instance; - tsap = sap; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - IRDA_ASSERT(tsap != NULL, return;); - IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); - - IRDA_ASSERT(tsap == self->client.tsap_ctrl, return;); - - /* Remove frames queued on the control channel */ - while ((skb = skb_dequeue(&self->client.txq)) != NULL) { - dev_kfree_skb(skb); - } - self->client.tx_busy = FALSE; - - irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); -} - -/* - * Function irlan_client_open_tsaps (self) - * - * Initialize callbacks and open IrTTP TSAPs - * - */ -static void irlan_client_open_ctrl_tsap(struct irlan_cb *self) -{ - struct tsap_cb *tsap; - notify_t notify; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Check if already open */ - if (self->client.tsap_ctrl) - return; - - irda_notify_init(¬ify); - - /* Set up callbacks */ - notify.data_indication = irlan_client_ctrl_data_indication; - notify.connect_confirm = irlan_client_ctrl_connect_confirm; - notify.disconnect_indication = irlan_client_ctrl_disconnect_indication; - notify.instance = self; - strlcpy(notify.name, "IrLAN ctrl (c)", sizeof(notify.name)); - - tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); - if (!tsap) { - pr_debug("%s(), Got no tsap!\n", __func__); - return; - } - self->client.tsap_ctrl = tsap; -} - -/* - * Function irlan_client_connect_confirm (handle, skb) - * - * Connection to peer IrLAN laye confirmed - * - */ -static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct irlan_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - self->client.max_sdu_size = max_sdu_size; - self->client.max_header_size = max_header_size; - - /* TODO: we could set the MTU depending on the max_sdu_size */ - - irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL); -} - -/* - * Function print_ret_code (code) - * - * Print return code of request to peer IrLAN layer. - * - */ -static void print_ret_code(__u8 code) -{ - switch(code) { - case 0: - printk(KERN_INFO "Success\n"); - break; - case 1: - net_warn_ratelimited("IrLAN: Insufficient resources\n"); - break; - case 2: - net_warn_ratelimited("IrLAN: Invalid command format\n"); - break; - case 3: - net_warn_ratelimited("IrLAN: Command not supported\n"); - break; - case 4: - net_warn_ratelimited("IrLAN: Parameter not supported\n"); - break; - case 5: - net_warn_ratelimited("IrLAN: Value not supported\n"); - break; - case 6: - net_warn_ratelimited("IrLAN: Not open\n"); - break; - case 7: - net_warn_ratelimited("IrLAN: Authentication required\n"); - break; - case 8: - net_warn_ratelimited("IrLAN: Invalid password\n"); - break; - case 9: - net_warn_ratelimited("IrLAN: Protocol error\n"); - break; - case 255: - net_warn_ratelimited("IrLAN: Asynchronous status\n"); - break; - } -} - -/* - * Function irlan_client_parse_response (self, skb) - * - * Extract all parameters from received buffer, then feed them to - * check_params for parsing - */ -void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb) -{ - __u8 *frame; - __u8 *ptr; - int count; - int ret; - __u16 val_len; - int i; - char *name; - char *value; - - IRDA_ASSERT(skb != NULL, return;); - - pr_debug("%s() skb->len=%d\n", __func__ , (int)skb->len); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - if (!skb) { - net_err_ratelimited("%s(), Got NULL skb!\n", __func__); - return; - } - frame = skb->data; - - /* - * Check return code and print it if not success - */ - if (frame[0]) { - print_ret_code(frame[0]); - return; - } - - name = kmalloc(255, GFP_ATOMIC); - if (!name) - return; - value = kmalloc(1016, GFP_ATOMIC); - if (!value) { - kfree(name); - return; - } - - /* How many parameters? */ - count = frame[1]; - - pr_debug("%s(), got %d parameters\n", __func__ , count); - - ptr = frame+2; - - /* For all parameters */ - for (i=0; i<count;i++) { - ret = irlan_extract_param(ptr, name, value, &val_len); - if (ret < 0) { - pr_debug("%s(), IrLAN, Error!\n", __func__); - break; - } - ptr += ret; - irlan_check_response_param(self, name, value, val_len); - } - /* Cleanup */ - kfree(name); - kfree(value); -} - -/* - * Function irlan_check_response_param (self, param, value, val_len) - * - * Check which parameter is received and update local variables - * - */ -static void irlan_check_response_param(struct irlan_cb *self, char *param, - char *value, int val_len) -{ - __u16 tmp_cpu; /* Temporary value in host order */ - __u8 *bytes; - int i; - - pr_debug("%s(), parm=%s\n", __func__ , param); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Media type */ - if (strcmp(param, "MEDIA") == 0) { - if (strcmp(value, "802.3") == 0) - self->media = MEDIA_802_3; - else - self->media = MEDIA_802_5; - return; - } - if (strcmp(param, "FILTER_TYPE") == 0) { - if (strcmp(value, "DIRECTED") == 0) - self->client.filter_type |= IRLAN_DIRECTED; - else if (strcmp(value, "FUNCTIONAL") == 0) - self->client.filter_type |= IRLAN_FUNCTIONAL; - else if (strcmp(value, "GROUP") == 0) - self->client.filter_type |= IRLAN_GROUP; - else if (strcmp(value, "MAC_FRAME") == 0) - self->client.filter_type |= IRLAN_MAC_FRAME; - else if (strcmp(value, "MULTICAST") == 0) - self->client.filter_type |= IRLAN_MULTICAST; - else if (strcmp(value, "BROADCAST") == 0) - self->client.filter_type |= IRLAN_BROADCAST; - else if (strcmp(value, "IPX_SOCKET") == 0) - self->client.filter_type |= IRLAN_IPX_SOCKET; - - } - if (strcmp(param, "ACCESS_TYPE") == 0) { - if (strcmp(value, "DIRECT") == 0) - self->client.access_type = ACCESS_DIRECT; - else if (strcmp(value, "PEER") == 0) - self->client.access_type = ACCESS_PEER; - else if (strcmp(value, "HOSTED") == 0) - self->client.access_type = ACCESS_HOSTED; - else { - pr_debug("%s(), unknown access type!\n", __func__); - } - } - /* IRLAN version */ - if (strcmp(param, "IRLAN_VER") == 0) { - pr_debug("IrLAN version %d.%d\n", (__u8)value[0], - (__u8)value[1]); - - self->version[0] = value[0]; - self->version[1] = value[1]; - return; - } - /* Which remote TSAP to use for data channel */ - if (strcmp(param, "DATA_CHAN") == 0) { - self->dtsap_sel_data = value[0]; - pr_debug("Data TSAP = %02x\n", self->dtsap_sel_data); - return; - } - if (strcmp(param, "CON_ARB") == 0) { - memcpy(&tmp_cpu, value, 2); /* Align value */ - le16_to_cpus(&tmp_cpu); /* Convert to host order */ - self->client.recv_arb_val = tmp_cpu; - pr_debug("%s(), receive arb val=%d\n", __func__ , - self->client.recv_arb_val); - } - if (strcmp(param, "MAX_FRAME") == 0) { - memcpy(&tmp_cpu, value, 2); /* Align value */ - le16_to_cpus(&tmp_cpu); /* Convert to host order */ - self->client.max_frame = tmp_cpu; - pr_debug("%s(), max frame=%d\n", __func__ , - self->client.max_frame); - } - - /* RECONNECT_KEY, in case the link goes down! */ - if (strcmp(param, "RECONNECT_KEY") == 0) { - pr_debug("Got reconnect key: "); - /* for (i = 0; i < val_len; i++) */ -/* printk("%02x", value[i]); */ - memcpy(self->client.reconnect_key, value, val_len); - self->client.key_len = val_len; - pr_debug("\n"); - } - /* FILTER_ENTRY, have we got an ethernet address? */ - if (strcmp(param, "FILTER_ENTRY") == 0) { - bytes = value; - pr_debug("Ethernet address = %pM\n", bytes); - for (i = 0; i < 6; i++) - self->dev->dev_addr[i] = bytes[i]; - } -} - -/* - * Function irlan_client_get_value_confirm (obj_id, value) - * - * Got results from remote LM-IAS - * - */ -void irlan_client_get_value_confirm(int result, __u16 obj_id, - struct ias_value *value, void *priv) -{ - struct irlan_cb *self; - - IRDA_ASSERT(priv != NULL, return;); - - self = priv; - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* We probably don't need to make any more queries */ - iriap_close(self->client.iriap); - self->client.iriap = NULL; - - /* Check if request succeeded */ - if (result != IAS_SUCCESS) { - pr_debug("%s(), got NULL value!\n", __func__); - irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, - NULL); - return; - } - - switch (value->type) { - case IAS_INTEGER: - self->dtsap_sel_ctrl = value->t.integer; - - if (value->t.integer != -1) { - irlan_do_client_event(self, IRLAN_IAS_PROVIDER_AVAIL, - NULL); - return; - } - irias_delete_value(value); - break; - default: - pr_debug("%s(), unknown type!\n", __func__); - break; - } - irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL); -} diff --git a/drivers/staging/irda/net/irlan/irlan_client_event.c b/drivers/staging/irda/net/irlan/irlan_client_event.c deleted file mode 100644 index cc93fabbbb19..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_client_event.c +++ /dev/null @@ -1,511 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_client_event.c - * Version: 0.9 - * Description: IrLAN client state machine - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Sun Dec 26 21:52:24 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/skbuff.h> - -#include <net/irda/irda.h> -#include <net/irda/timer.h> -#include <net/irda/irmod.h> -#include <net/irda/iriap.h> -#include <net/irda/irlmp.h> -#include <net/irda/irttp.h> - -#include <net/irda/irlan_common.h> -#include <net/irda/irlan_client.h> -#include <net/irda/irlan_event.h> - -static int irlan_client_state_idle (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_conn (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_info (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_open (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_wait (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_arb (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_data (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_client_state_sync (struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); - -static int (*state[])(struct irlan_cb *, IRLAN_EVENT event, struct sk_buff *) = -{ - irlan_client_state_idle, - irlan_client_state_query, - irlan_client_state_conn, - irlan_client_state_info, - irlan_client_state_media, - irlan_client_state_open, - irlan_client_state_wait, - irlan_client_state_arb, - irlan_client_state_data, - irlan_client_state_close, - irlan_client_state_sync -}; - -void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - (*state[ self->client.state]) (self, event, skb); -} - -/* - * Function irlan_client_state_idle (event, skb, info) - * - * IDLE, We are waiting for an indication that there is a provider - * available. - */ -static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - - switch (event) { - case IRLAN_DISCOVERY_INDICATION: - if (self->client.iriap) { - net_warn_ratelimited("%s(), busy with a previous query\n", - __func__); - return -EBUSY; - } - - self->client.iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - irlan_client_get_value_confirm); - /* Get some values from peer IAS */ - irlan_next_client_state(self, IRLAN_QUERY); - iriap_getvaluebyclass_request(self->client.iriap, - self->saddr, self->daddr, - "IrLAN", "IrDA:TinyTP:LsapSel"); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_query (event, skb, info) - * - * QUERY, We have queryed the remote IAS and is ready to connect - * to provider, just waiting for the confirm. - * - */ -static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - - switch(event) { - case IRLAN_IAS_PROVIDER_AVAIL: - IRDA_ASSERT(self->dtsap_sel_ctrl != 0, return -1;); - - self->client.open_retries = 0; - - irttp_connect_request(self->client.tsap_ctrl, - self->dtsap_sel_ctrl, - self->saddr, self->daddr, NULL, - IRLAN_MTU, NULL); - irlan_next_client_state(self, IRLAN_CONN); - break; - case IRLAN_IAS_PROVIDER_NOT_AVAIL: - pr_debug("%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__); - irlan_next_client_state(self, IRLAN_IDLE); - - /* Give the client a kick! */ - if ((self->provider.access_type == ACCESS_PEER) && - (self->provider.state != IRLAN_IDLE)) - irlan_client_wakeup(self, self->saddr, self->daddr); - break; - case IRLAN_LMP_DISCONNECT: - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_conn (event, skb, info) - * - * CONN, We have connected to a provider but has not issued any - * commands yet. - * - */ -static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - - switch (event) { - case IRLAN_CONNECT_COMPLETE: - /* Send getinfo cmd */ - irlan_get_provider_info(self); - irlan_next_client_state(self, IRLAN_INFO); - break; - case IRLAN_LMP_DISCONNECT: - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_info (self, event, skb, info) - * - * INFO, We have issued a GetInfo command and is awaiting a reply. - */ -static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - - switch (event) { - case IRLAN_DATA_INDICATION: - IRDA_ASSERT(skb != NULL, return -1;); - - irlan_client_parse_response(self, skb); - - irlan_next_client_state(self, IRLAN_MEDIA); - - irlan_get_media_char(self); - break; - - case IRLAN_LMP_DISCONNECT: - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_media (self, event, skb, info) - * - * MEDIA, The irlan_client has issued a GetMedia command and is awaiting a - * reply. - * - */ -static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - - switch(event) { - case IRLAN_DATA_INDICATION: - irlan_client_parse_response(self, skb); - irlan_open_data_channel(self); - irlan_next_client_state(self, IRLAN_OPEN); - break; - case IRLAN_LMP_DISCONNECT: - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_open (self, event, skb, info) - * - * OPEN, The irlan_client has issued a OpenData command and is awaiting a - * reply - * - */ -static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - struct qos_info qos; - - IRDA_ASSERT(self != NULL, return -1;); - - switch(event) { - case IRLAN_DATA_INDICATION: - irlan_client_parse_response(self, skb); - - /* - * Check if we have got the remote TSAP for data - * communications - */ - IRDA_ASSERT(self->dtsap_sel_data != 0, return -1;); - - /* Check which access type we are dealing with */ - switch (self->client.access_type) { - case ACCESS_PEER: - if (self->provider.state == IRLAN_OPEN) { - - irlan_next_client_state(self, IRLAN_ARB); - irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, - NULL); - } else { - - irlan_next_client_state(self, IRLAN_WAIT); - } - break; - case ACCESS_DIRECT: - case ACCESS_HOSTED: - qos.link_disc_time.bits = 0x01; /* 3 secs */ - - irttp_connect_request(self->tsap_data, - self->dtsap_sel_data, - self->saddr, self->daddr, &qos, - IRLAN_MTU, NULL); - - irlan_next_client_state(self, IRLAN_DATA); - break; - default: - pr_debug("%s(), unknown access type!\n", __func__); - break; - } - break; - case IRLAN_LMP_DISCONNECT: - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_wait (self, event, skb, info) - * - * WAIT, The irlan_client is waiting for the local provider to enter the - * provider OPEN state. - * - */ -static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - - switch(event) { - case IRLAN_PROVIDER_SIGNAL: - irlan_next_client_state(self, IRLAN_ARB); - irlan_do_client_event(self, IRLAN_CHECK_CON_ARB, NULL); - break; - case IRLAN_LMP_DISCONNECT: - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - struct qos_info qos; - - IRDA_ASSERT(self != NULL, return -1;); - - switch(event) { - case IRLAN_CHECK_CON_ARB: - if (self->client.recv_arb_val == self->provider.send_arb_val) { - irlan_next_client_state(self, IRLAN_CLOSE); - irlan_close_data_channel(self); - } else if (self->client.recv_arb_val < - self->provider.send_arb_val) - { - qos.link_disc_time.bits = 0x01; /* 3 secs */ - - irlan_next_client_state(self, IRLAN_DATA); - irttp_connect_request(self->tsap_data, - self->dtsap_sel_data, - self->saddr, self->daddr, &qos, - IRLAN_MTU, NULL); - } else if (self->client.recv_arb_val > - self->provider.send_arb_val) - { - pr_debug("%s(), lost the battle :-(\n", __func__); - } - break; - case IRLAN_DATA_CONNECT_INDICATION: - irlan_next_client_state(self, IRLAN_DATA); - break; - case IRLAN_LMP_DISCONNECT: - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - case IRLAN_WATCHDOG_TIMEOUT: - pr_debug("%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_data (self, event, skb, info) - * - * DATA, The data channel is connected, allowing data transfers between - * the local and remote machines. - * - */ -static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - - switch(event) { - case IRLAN_DATA_INDICATION: - irlan_client_parse_response(self, skb); - break; - case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ - case IRLAN_LAP_DISCONNECT: - irlan_next_client_state(self, IRLAN_IDLE); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_close (self, event, skb, info) - * - * - * - */ -static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_client_state_sync (self, event, skb, info) - * - * - * - */ -static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - if (skb) - dev_kfree_skb(skb); - - return 0; -} - - - - - - - - - - - - - diff --git a/drivers/staging/irda/net/irlan/irlan_common.c b/drivers/staging/irda/net/irlan/irlan_common.c deleted file mode 100644 index fdcd7147007d..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_common.c +++ /dev/null @@ -1,1176 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_common.c - * Version: 0.9 - * Description: IrDA LAN Access Protocol Implementation - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Sun Dec 26 21:53:10 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/gfp.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/proc_fs.h> -#include <linux/sched.h> -#include <linux/seq_file.h> -#include <linux/random.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/rtnetlink.h> -#include <linux/moduleparam.h> -#include <linux/bitops.h> - -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/irttp.h> -#include <net/irda/irlmp.h> -#include <net/irda/iriap.h> -#include <net/irda/timer.h> - -#include <net/irda/irlan_common.h> -#include <net/irda/irlan_client.h> -#include <net/irda/irlan_provider.h> -#include <net/irda/irlan_eth.h> -#include <net/irda/irlan_filter.h> - - -/* extern char sysctl_devname[]; */ - -/* - * Master structure - */ -static LIST_HEAD(irlans); - -static void *ckey; -static void *skey; - -/* Module parameters */ -static bool eth; /* Use "eth" or "irlan" name for devices */ -static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */ - -#ifdef CONFIG_PROC_FS -static const char *const irlan_access[] = { - "UNKNOWN", - "DIRECT", - "PEER", - "HOSTED" -}; - -static const char *const irlan_media[] = { - "UNKNOWN", - "802.3", - "802.5" -}; - -extern struct proc_dir_entry *proc_irda; - -static int irlan_seq_open(struct inode *inode, struct file *file); - -static const struct file_operations irlan_fops = { - .owner = THIS_MODULE, - .open = irlan_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -extern struct proc_dir_entry *proc_irda; -#endif /* CONFIG_PROC_FS */ - -static struct irlan_cb __init *irlan_open(__u32 saddr, __u32 daddr); -static void __irlan_close(struct irlan_cb *self); -static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, - __u8 value_byte, __u16 value_short, - __u8 *value_array, __u16 value_len); -static void irlan_open_unicast_addr(struct irlan_cb *self); -static void irlan_get_unicast_addr(struct irlan_cb *self); -void irlan_close_tsaps(struct irlan_cb *self); - -/* - * Function irlan_init (void) - * - * Initialize IrLAN layer - * - */ -static int __init irlan_init(void) -{ - struct irlan_cb *new; - __u16 hints; - -#ifdef CONFIG_PROC_FS - { struct proc_dir_entry *proc; - proc = proc_create("irlan", 0, proc_irda, &irlan_fops); - if (!proc) { - printk(KERN_ERR "irlan_init: can't create /proc entry!\n"); - return -ENODEV; - } - } -#endif /* CONFIG_PROC_FS */ - - hints = irlmp_service_to_hint(S_LAN); - - /* Register with IrLMP as a client */ - ckey = irlmp_register_client(hints, &irlan_client_discovery_indication, - NULL, NULL); - if (!ckey) - goto err_ckey; - - /* Register with IrLMP as a service */ - skey = irlmp_register_service(hints); - if (!skey) - goto err_skey; - - /* Start the master IrLAN instance (the only one for now) */ - new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY); - if (!new) - goto err_open; - - /* The master will only open its (listen) control TSAP */ - irlan_provider_open_ctrl_tsap(new); - - /* Do some fast discovery! */ - irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); - - return 0; - -err_open: - irlmp_unregister_service(skey); -err_skey: - irlmp_unregister_client(ckey); -err_ckey: -#ifdef CONFIG_PROC_FS - remove_proc_entry("irlan", proc_irda); -#endif /* CONFIG_PROC_FS */ - - return -ENOMEM; -} - -static void __exit irlan_cleanup(void) -{ - struct irlan_cb *self, *next; - - irlmp_unregister_client(ckey); - irlmp_unregister_service(skey); - -#ifdef CONFIG_PROC_FS - remove_proc_entry("irlan", proc_irda); -#endif /* CONFIG_PROC_FS */ - - /* Cleanup any leftover network devices */ - rtnl_lock(); - list_for_each_entry_safe(self, next, &irlans, dev_list) { - __irlan_close(self); - } - rtnl_unlock(); -} - -/* - * Function irlan_open (void) - * - * Open new instance of a client/provider, we should only register the - * network device if this instance is ment for a particular client/provider - */ -static struct irlan_cb __init *irlan_open(__u32 saddr, __u32 daddr) -{ - struct net_device *dev; - struct irlan_cb *self; - - /* Create network device with irlan */ - dev = alloc_irlandev(eth ? "eth%d" : "irlan%d"); - if (!dev) - return NULL; - - self = netdev_priv(dev); - self->dev = dev; - - /* - * Initialize local device structure - */ - self->magic = IRLAN_MAGIC; - self->saddr = saddr; - self->daddr = daddr; - - /* Provider access can only be PEER, DIRECT, or HOSTED */ - self->provider.access_type = access; - if (access == ACCESS_DIRECT) { - /* - * Since we are emulating an IrLAN sever we will have to - * give ourself an ethernet address! - */ - dev->dev_addr[0] = 0x40; - dev->dev_addr[1] = 0x00; - dev->dev_addr[2] = 0x00; - dev->dev_addr[3] = 0x00; - get_random_bytes(dev->dev_addr+4, 1); - get_random_bytes(dev->dev_addr+5, 1); - } - - self->media = MEDIA_802_3; - self->disconnect_reason = LM_USER_REQUEST; - timer_setup(&self->watchdog_timer, NULL, 0); - timer_setup(&self->client.kick_timer, NULL, 0); - init_waitqueue_head(&self->open_wait); - - skb_queue_head_init(&self->client.txq); - - irlan_next_client_state(self, IRLAN_IDLE); - irlan_next_provider_state(self, IRLAN_IDLE); - - if (register_netdev(dev)) { - pr_debug("%s(), register_netdev() failed!\n", - __func__); - self = NULL; - free_netdev(dev); - } else { - rtnl_lock(); - list_add_rcu(&self->dev_list, &irlans); - rtnl_unlock(); - } - - return self; -} -/* - * Function __irlan_close (self) - * - * This function closes and deallocates the IrLAN client instances. Be - * aware that other functions which calls client_close() must - * remove self from irlans list first. - */ -static void __irlan_close(struct irlan_cb *self) -{ - ASSERT_RTNL(); - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - del_timer_sync(&self->watchdog_timer); - del_timer_sync(&self->client.kick_timer); - - /* Close all open connections and remove TSAPs */ - irlan_close_tsaps(self); - - if (self->client.iriap) - iriap_close(self->client.iriap); - - /* Remove frames queued on the control channel */ - skb_queue_purge(&self->client.txq); - - /* Unregister and free self via destructor */ - unregister_netdevice(self->dev); -} - -/* Find any instance of irlan, used for client discovery wakeup */ -struct irlan_cb *irlan_get_any(void) -{ - struct irlan_cb *self; - - list_for_each_entry_rcu(self, &irlans, dev_list) { - return self; - } - return NULL; -} - -/* - * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb) - * - * Here we receive the connect indication for the data channel - * - */ -static void irlan_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct irlan_cb *self; - struct tsap_cb *tsap; - - self = instance; - tsap = sap; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - IRDA_ASSERT(tsap == self->tsap_data,return;); - - self->max_sdu_size = max_sdu_size; - self->max_header_size = max_header_size; - - pr_debug("%s: We are now connected!\n", __func__); - - del_timer(&self->watchdog_timer); - - /* If you want to pass the skb to *both* state machines, you will - * need to skb_clone() it, so that you don't free it twice. - * As the state machines don't need it, git rid of it here... - * Jean II */ - if (skb) - dev_kfree_skb(skb); - - irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); - irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, NULL); - - if (self->provider.access_type == ACCESS_PEER) { - /* - * Data channel is open, so we are now allowed to - * configure the remote filter - */ - irlan_get_unicast_addr(self); - irlan_open_unicast_addr(self); - } - /* Ready to transfer Ethernet frames (at last) */ - netif_start_queue(self->dev); /* Clear reason */ -} - -static void irlan_connect_confirm(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct irlan_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - self->max_sdu_size = max_sdu_size; - self->max_header_size = max_header_size; - - /* TODO: we could set the MTU depending on the max_sdu_size */ - - pr_debug("%s: We are now connected!\n", __func__); - del_timer(&self->watchdog_timer); - - /* - * Data channel is open, so we are now allowed to configure the remote - * filter - */ - irlan_get_unicast_addr(self); - irlan_open_unicast_addr(self); - - /* Open broadcast and multicast filter by default */ - irlan_set_broadcast_filter(self, TRUE); - irlan_set_multicast_filter(self, TRUE); - - /* Ready to transfer Ethernet frames */ - netif_start_queue(self->dev); - self->disconnect_reason = 0; /* Clear reason */ - wake_up_interruptible(&self->open_wait); -} - -/* - * Function irlan_client_disconnect_indication (handle) - * - * Callback function for the IrTTP layer. Indicates a disconnection of - * the specified connection (handle) - */ -static void irlan_disconnect_indication(void *instance, - void *sap, LM_REASON reason, - struct sk_buff *userdata) -{ - struct irlan_cb *self; - struct tsap_cb *tsap; - - pr_debug("%s(), reason=%d\n", __func__ , reason); - - self = instance; - tsap = sap; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - IRDA_ASSERT(tsap != NULL, return;); - IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); - - IRDA_ASSERT(tsap == self->tsap_data, return;); - - pr_debug("IrLAN, data channel disconnected by peer!\n"); - - /* Save reason so we know if we should try to reconnect or not */ - self->disconnect_reason = reason; - - switch (reason) { - case LM_USER_REQUEST: /* User request */ - pr_debug("%s(), User requested\n", __func__); - break; - case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */ - pr_debug("%s(), Unexpected IrLAP disconnect\n", __func__); - break; - case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */ - pr_debug("%s(), IrLAP connect failed\n", __func__); - break; - case LM_LAP_RESET: /* IrLAP reset */ - pr_debug("%s(), IrLAP reset\n", __func__); - break; - case LM_INIT_DISCONNECT: - pr_debug("%s(), IrLMP connect failed\n", __func__); - break; - default: - net_err_ratelimited("%s(), Unknown disconnect reason\n", - __func__); - break; - } - - /* If you want to pass the skb to *both* state machines, you will - * need to skb_clone() it, so that you don't free it twice. - * As the state machines don't need it, git rid of it here... - * Jean II */ - if (userdata) - dev_kfree_skb(userdata); - - irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); - irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); - - wake_up_interruptible(&self->open_wait); -} - -void irlan_open_data_tsap(struct irlan_cb *self) -{ - struct tsap_cb *tsap; - notify_t notify; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Check if already open */ - if (self->tsap_data) - return; - - irda_notify_init(¬ify); - - notify.data_indication = irlan_eth_receive; - notify.udata_indication = irlan_eth_receive; - notify.connect_indication = irlan_connect_indication; - notify.connect_confirm = irlan_connect_confirm; - notify.flow_indication = irlan_eth_flow_indication; - notify.disconnect_indication = irlan_disconnect_indication; - notify.instance = self; - strlcpy(notify.name, "IrLAN data", sizeof(notify.name)); - - tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); - if (!tsap) { - pr_debug("%s(), Got no tsap!\n", __func__); - return; - } - self->tsap_data = tsap; - - /* - * This is the data TSAP selector which we will pass to the client - * when the client ask for it. - */ - self->stsap_sel_data = self->tsap_data->stsap_sel; -} - -void irlan_close_tsaps(struct irlan_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Disconnect and close all open TSAP connections */ - if (self->tsap_data) { - irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL); - irttp_close_tsap(self->tsap_data); - self->tsap_data = NULL; - } - if (self->client.tsap_ctrl) { - irttp_disconnect_request(self->client.tsap_ctrl, NULL, - P_NORMAL); - irttp_close_tsap(self->client.tsap_ctrl); - self->client.tsap_ctrl = NULL; - } - if (self->provider.tsap_ctrl) { - irttp_disconnect_request(self->provider.tsap_ctrl, NULL, - P_NORMAL); - irttp_close_tsap(self->provider.tsap_ctrl); - self->provider.tsap_ctrl = NULL; - } - self->disconnect_reason = LM_USER_REQUEST; -} - -/* - * Function irlan_ias_register (self, tsap_sel) - * - * Register with LM-IAS - * - */ -void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel) -{ - struct ias_object *obj; - struct ias_value *new_value; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* - * Check if object has already been registered by a previous provider. - * If that is the case, we just change the value of the attribute - */ - if (!irias_find_object("IrLAN")) { - obj = irias_new_object("IrLAN", IAS_IRLAN_ID); - irias_add_integer_attrib(obj, "IrDA:TinyTP:LsapSel", tsap_sel, - IAS_KERNEL_ATTR); - irias_insert_object(obj); - } else { - new_value = irias_new_integer_value(tsap_sel); - irias_object_change_attribute("IrLAN", "IrDA:TinyTP:LsapSel", - new_value); - } - - /* Register PnP object only if not registered before */ - if (!irias_find_object("PnP")) { - obj = irias_new_object("PnP", IAS_PNP_ID); -#if 0 - irias_add_string_attrib(obj, "Name", sysctl_devname, - IAS_KERNEL_ATTR); -#else - irias_add_string_attrib(obj, "Name", "Linux", IAS_KERNEL_ATTR); -#endif - irias_add_string_attrib(obj, "DeviceID", "HWP19F0", - IAS_KERNEL_ATTR); - irias_add_integer_attrib(obj, "CompCnt", 1, IAS_KERNEL_ATTR); - if (self->provider.access_type == ACCESS_PEER) - irias_add_string_attrib(obj, "Comp#01", "PNP8389", - IAS_KERNEL_ATTR); - else - irias_add_string_attrib(obj, "Comp#01", "PNP8294", - IAS_KERNEL_ATTR); - - irias_add_string_attrib(obj, "Manufacturer", - "Linux-IrDA Project", IAS_KERNEL_ATTR); - irias_insert_object(obj); - } -} - -/* - * Function irlan_run_ctrl_tx_queue (self) - * - * Try to send the next command in the control transmit queue - * - */ -int irlan_run_ctrl_tx_queue(struct irlan_cb *self) -{ - struct sk_buff *skb; - - if (irda_lock(&self->client.tx_busy) == FALSE) - return -EBUSY; - - skb = skb_dequeue(&self->client.txq); - if (!skb) { - self->client.tx_busy = FALSE; - return 0; - } - - /* Check that it's really possible to send commands */ - if ((self->client.tsap_ctrl == NULL) || - (self->client.state == IRLAN_IDLE)) - { - self->client.tx_busy = FALSE; - dev_kfree_skb(skb); - return -1; - } - pr_debug("%s(), sending ...\n", __func__); - - return irttp_data_request(self->client.tsap_ctrl, skb); -} - -/* - * Function irlan_ctrl_data_request (self, skb) - * - * This function makes sure that commands on the control channel is being - * sent in a command/response fashion - */ -static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb) -{ - /* Queue command */ - skb_queue_tail(&self->client.txq, skb); - - /* Try to send command */ - irlan_run_ctrl_tx_queue(self); -} - -/* - * Function irlan_get_provider_info (self) - * - * Send Get Provider Information command to peer IrLAN layer - * - */ -void irlan_get_provider_info(struct irlan_cb *self) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER, - GFP_ATOMIC); - if (!skb) - return; - - /* Reserve space for TTP, LMP, and LAP header */ - skb_reserve(skb, self->client.max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - frame[0] = CMD_GET_PROVIDER_INFO; - frame[1] = 0x00; /* Zero parameters */ - - irlan_ctrl_data_request(self, skb); -} - -/* - * Function irlan_open_data_channel (self) - * - * Send an Open Data Command to provider - * - */ -void irlan_open_data_channel(struct irlan_cb *self) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3") + - IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "DIRECT"), - GFP_ATOMIC); - if (!skb) - return; - - skb_reserve(skb, self->client.max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - /* Build frame */ - frame[0] = CMD_OPEN_DATA_CHANNEL; - frame[1] = 0x02; /* Two parameters */ - - irlan_insert_string_param(skb, "MEDIA", "802.3"); - irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT"); - /* irlan_insert_string_param(skb, "MODE", "UNRELIABLE"); */ - -/* self->use_udata = TRUE; */ - - irlan_ctrl_data_request(self, skb); -} - -void irlan_close_data_channel(struct irlan_cb *self) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Check if the TSAP is still there */ - if (self->client.tsap_ctrl == NULL) - return; - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN"), - GFP_ATOMIC); - if (!skb) - return; - - skb_reserve(skb, self->client.max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - /* Build frame */ - frame[0] = CMD_CLOSE_DATA_CHAN; - frame[1] = 0x01; /* One parameter */ - - irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); - - irlan_ctrl_data_request(self, skb); -} - -/* - * Function irlan_open_unicast_addr (self) - * - * Make IrLAN provider accept ethernet frames addressed to the unicast - * address. - * - */ -static void irlan_open_unicast_addr(struct irlan_cb *self) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + - IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") + - IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"), - GFP_ATOMIC); - if (!skb) - return; - - /* Reserve space for TTP, LMP, and LAP header */ - skb_reserve(skb, self->max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - frame[0] = CMD_FILTER_OPERATION; - frame[1] = 0x03; /* Three parameters */ - irlan_insert_byte_param(skb, "DATA_CHAN" , self->dtsap_sel_data); - irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); - irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); - - irlan_ctrl_data_request(self, skb); -} - -/* - * Function irlan_set_broadcast_filter (self, status) - * - * Make IrLAN provider accept ethernet frames addressed to the broadcast - * address. Be careful with the use of this one, since there may be a lot - * of broadcast traffic out there. We can still function without this - * one but then _we_ have to initiate all communication with other - * hosts, since ARP request for this host will not be answered. - */ -void irlan_set_broadcast_filter(struct irlan_cb *self, int status) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + - IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") + - /* We may waste one byte here...*/ - IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"), - GFP_ATOMIC); - if (!skb) - return; - - /* Reserve space for TTP, LMP, and LAP header */ - skb_reserve(skb, self->client.max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - frame[0] = CMD_FILTER_OPERATION; - frame[1] = 0x03; /* Three parameters */ - irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); - irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST"); - if (status) - irlan_insert_string_param(skb, "FILTER_MODE", "FILTER"); - else - irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); - - irlan_ctrl_data_request(self, skb); -} - -/* - * Function irlan_set_multicast_filter (self, status) - * - * Make IrLAN provider accept ethernet frames addressed to the multicast - * address. - * - */ -void irlan_set_multicast_filter(struct irlan_cb *self, int status) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + - IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") + - /* We may waste one byte here...*/ - IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "NONE"), - GFP_ATOMIC); - if (!skb) - return; - - /* Reserve space for TTP, LMP, and LAP header */ - skb_reserve(skb, self->client.max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - frame[0] = CMD_FILTER_OPERATION; - frame[1] = 0x03; /* Three parameters */ - irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); - irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST"); - if (status) - irlan_insert_string_param(skb, "FILTER_MODE", "ALL"); - else - irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); - - irlan_ctrl_data_request(self, skb); -} - -/* - * Function irlan_get_unicast_addr (self) - * - * Retrieves the unicast address from the IrLAN provider. This address - * will be inserted into the devices structure, so the ethernet layer - * can construct its packets. - * - */ -static void irlan_get_unicast_addr(struct irlan_cb *self) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") + - IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") + - IRLAN_STRING_PARAMETER_LEN("FILTER_OPERATION", - "DYNAMIC"), - GFP_ATOMIC); - if (!skb) - return; - - /* Reserve space for TTP, LMP, and LAP header */ - skb_reserve(skb, self->client.max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - frame[0] = CMD_FILTER_OPERATION; - frame[1] = 0x03; /* Three parameters */ - irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data); - irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); - irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC"); - - irlan_ctrl_data_request(self, skb); -} - -/* - * Function irlan_get_media_char (self) - * - * - * - */ -void irlan_get_media_char(struct irlan_cb *self) -{ - struct sk_buff *skb; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3"), - GFP_ATOMIC); - - if (!skb) - return; - - /* Reserve space for TTP, LMP, and LAP header */ - skb_reserve(skb, self->client.max_header_size); - skb_put(skb, 2); - - frame = skb->data; - - /* Build frame */ - frame[0] = CMD_GET_MEDIA_CHAR; - frame[1] = 0x01; /* One parameter */ - - irlan_insert_string_param(skb, "MEDIA", "802.3"); - irlan_ctrl_data_request(self, skb); -} - -/* - * Function insert_byte_param (skb, param, value) - * - * Insert byte parameter into frame - * - */ -int irlan_insert_byte_param(struct sk_buff *skb, char *param, __u8 value) -{ - return __irlan_insert_param(skb, param, IRLAN_BYTE, value, 0, NULL, 0); -} - -int irlan_insert_short_param(struct sk_buff *skb, char *param, __u16 value) -{ - return __irlan_insert_param(skb, param, IRLAN_SHORT, 0, value, NULL, 0); -} - -/* - * Function insert_string (skb, param, value) - * - * Insert string parameter into frame - * - */ -int irlan_insert_string_param(struct sk_buff *skb, char *param, char *string) -{ - int string_len = strlen(string); - - return __irlan_insert_param(skb, param, IRLAN_ARRAY, 0, 0, string, - string_len); -} - -/* - * Function insert_array_param(skb, param, value, len_value) - * - * Insert array parameter into frame - * - */ -int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *array, - __u16 array_len) -{ - return __irlan_insert_param(skb, name, IRLAN_ARRAY, 0, 0, array, - array_len); -} - -/* - * Function insert_param (skb, param, value, byte) - * - * Insert parameter at end of buffer, structure of a parameter is: - * - * ----------------------------------------------------------------------- - * | Name Length[1] | Param Name[1..255] | Val Length[2] | Value[0..1016]| - * ----------------------------------------------------------------------- - */ -static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, - __u8 value_byte, __u16 value_short, - __u8 *value_array, __u16 value_len) -{ - __u8 *frame; - __u8 param_len; - __le16 tmp_le; /* Temporary value in little endian format */ - int n=0; - - if (skb == NULL) { - pr_debug("%s(), Got NULL skb\n", __func__); - return 0; - } - - param_len = strlen(param); - switch (type) { - case IRLAN_BYTE: - value_len = 1; - break; - case IRLAN_SHORT: - value_len = 2; - break; - case IRLAN_ARRAY: - IRDA_ASSERT(value_array != NULL, return 0;); - IRDA_ASSERT(value_len > 0, return 0;); - break; - default: - pr_debug("%s(), Unknown parameter type!\n", __func__); - return 0; - } - - /* Insert at end of sk-buffer */ - frame = skb_tail_pointer(skb); - - /* Make space for data */ - if (skb_tailroom(skb) < (param_len+value_len+3)) { - pr_debug("%s(), No more space at end of skb\n", __func__); - return 0; - } - skb_put(skb, param_len+value_len+3); - - /* Insert parameter length */ - frame[n++] = param_len; - - /* Insert parameter */ - memcpy(frame+n, param, param_len); n += param_len; - - /* Insert value length (2 byte little endian format, LSB first) */ - tmp_le = cpu_to_le16(value_len); - memcpy(frame+n, &tmp_le, 2); n += 2; /* To avoid alignment problems */ - - /* Insert value */ - switch (type) { - case IRLAN_BYTE: - frame[n++] = value_byte; - break; - case IRLAN_SHORT: - tmp_le = cpu_to_le16(value_short); - memcpy(frame+n, &tmp_le, 2); n += 2; - break; - case IRLAN_ARRAY: - memcpy(frame+n, value_array, value_len); n+=value_len; - break; - default: - break; - } - IRDA_ASSERT(n == (param_len+value_len+3), return 0;); - - return param_len+value_len+3; -} - -/* - * Function irlan_extract_param (buf, name, value, len) - * - * Extracts a single parameter name/value pair from buffer and updates - * the buffer pointer to point to the next name/value pair. - */ -int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) -{ - __u8 name_len; - __u16 val_len; - int n=0; - - /* get length of parameter name (1 byte) */ - name_len = buf[n++]; - - if (name_len > 254) { - pr_debug("%s(), name_len > 254\n", __func__); - return -RSP_INVALID_COMMAND_FORMAT; - } - - /* get parameter name */ - memcpy(name, buf+n, name_len); - name[name_len] = '\0'; - n+=name_len; - - /* - * Get length of parameter value (2 bytes in little endian - * format) - */ - memcpy(&val_len, buf+n, 2); /* To avoid alignment problems */ - le16_to_cpus(&val_len); n+=2; - - if (val_len >= 1016) { - pr_debug("%s(), parameter length to long\n", __func__); - return -RSP_INVALID_COMMAND_FORMAT; - } - *len = val_len; - - /* get parameter value */ - memcpy(value, buf+n, val_len); - value[val_len] = '\0'; - n+=val_len; - - pr_debug("Parameter: %s ", name); - pr_debug("Value: %s\n", value); - - return n; -} - -#ifdef CONFIG_PROC_FS - -/* - * Start of reading /proc entries. - * Return entry at pos, - * or start_token to indicate print header line - * or NULL if end of file - */ -static void *irlan_seq_start(struct seq_file *seq, loff_t *pos) -{ - rcu_read_lock(); - return seq_list_start_head(&irlans, *pos); -} - -/* Return entry after v, and increment pos */ -static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_list_next(v, &irlans, pos); -} - -/* End of reading /proc file */ -static void irlan_seq_stop(struct seq_file *seq, void *v) -{ - rcu_read_unlock(); -} - - -/* - * Show one entry in /proc file. - */ -static int irlan_seq_show(struct seq_file *seq, void *v) -{ - if (v == &irlans) - seq_puts(seq, "IrLAN instances:\n"); - else { - struct irlan_cb *self = list_entry(v, struct irlan_cb, dev_list); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - - seq_printf(seq,"ifname: %s,\n", - self->dev->name); - seq_printf(seq,"client state: %s, ", - irlan_state[ self->client.state]); - seq_printf(seq,"provider state: %s,\n", - irlan_state[ self->provider.state]); - seq_printf(seq,"saddr: %#08x, ", - self->saddr); - seq_printf(seq,"daddr: %#08x\n", - self->daddr); - seq_printf(seq,"version: %d.%d,\n", - self->version[1], self->version[0]); - seq_printf(seq,"access type: %s\n", - irlan_access[self->client.access_type]); - seq_printf(seq,"media: %s\n", - irlan_media[self->media]); - - seq_printf(seq,"local filter:\n"); - seq_printf(seq,"remote filter: "); - irlan_print_filter(seq, self->client.filter_type); - seq_printf(seq,"tx busy: %s\n", - netif_queue_stopped(self->dev) ? "TRUE" : "FALSE"); - - seq_putc(seq,'\n'); - } - return 0; -} - -static const struct seq_operations irlan_seq_ops = { - .start = irlan_seq_start, - .next = irlan_seq_next, - .stop = irlan_seq_stop, - .show = irlan_seq_show, -}; - -static int irlan_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &irlan_seq_ops); -} -#endif - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("The Linux IrDA LAN protocol"); -MODULE_LICENSE("GPL"); - -module_param(eth, bool, 0); -MODULE_PARM_DESC(eth, "Name devices ethX (0) or irlanX (1)"); -module_param(access, int, 0); -MODULE_PARM_DESC(access, "Access type DIRECT=1, PEER=2, HOSTED=3"); - -module_init(irlan_init); -module_exit(irlan_cleanup); - diff --git a/drivers/staging/irda/net/irlan/irlan_eth.c b/drivers/staging/irda/net/irlan/irlan_eth.c deleted file mode 100644 index 3be852808a9d..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_eth.c +++ /dev/null @@ -1,340 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_eth.c - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Thu Oct 15 08:37:58 1998 - * Modified at: Tue Mar 21 09:06:41 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> - * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> - * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> - * - * Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/inetdevice.h> -#include <linux/if_arp.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <net/arp.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> -#include <net/irda/irlan_common.h> -#include <net/irda/irlan_client.h> -#include <net/irda/irlan_event.h> -#include <net/irda/irlan_eth.h> - -static int irlan_eth_open(struct net_device *dev); -static int irlan_eth_close(struct net_device *dev); -static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, - struct net_device *dev); -static void irlan_eth_set_multicast_list(struct net_device *dev); - -static const struct net_device_ops irlan_eth_netdev_ops = { - .ndo_open = irlan_eth_open, - .ndo_stop = irlan_eth_close, - .ndo_start_xmit = irlan_eth_xmit, - .ndo_set_rx_mode = irlan_eth_set_multicast_list, - .ndo_validate_addr = eth_validate_addr, -}; - -/* - * Function irlan_eth_setup (dev) - * - * The network device initialization function. - * - */ -static void irlan_eth_setup(struct net_device *dev) -{ - ether_setup(dev); - - dev->netdev_ops = &irlan_eth_netdev_ops; - dev->needs_free_netdev = true; - dev->min_mtu = 0; - dev->max_mtu = ETH_MAX_MTU; - - /* - * Lets do all queueing in IrTTP instead of this device driver. - * Queueing here as well can introduce some strange latency - * problems, which we will avoid by setting the queue size to 0. - */ - /* - * The bugs in IrTTP and IrLAN that created this latency issue - * have now been fixed, and we can propagate flow control properly - * to the network layer. However, this requires a minimal queue of - * packets for the device. - * Without flow control, the Tx Queue is 14 (ttp) + 0 (dev) = 14 - * With flow control, the Tx Queue is 7 (ttp) + 4 (dev) = 11 - * See irlan_eth_flow_indication()... - * Note : this number was randomly selected and would need to - * be adjusted. - * Jean II */ - dev->tx_queue_len = 4; -} - -/* - * Function alloc_irlandev - * - * Allocate network device and control block - * - */ -struct net_device *alloc_irlandev(const char *name) -{ - return alloc_netdev(sizeof(struct irlan_cb), name, NET_NAME_UNKNOWN, - irlan_eth_setup); -} - -/* - * Function irlan_eth_open (dev) - * - * Network device has been opened by user - * - */ -static int irlan_eth_open(struct net_device *dev) -{ - struct irlan_cb *self = netdev_priv(dev); - - /* Ready to play! */ - netif_stop_queue(dev); /* Wait until data link is ready */ - - /* We are now open, so time to do some work */ - self->disconnect_reason = 0; - irlan_client_wakeup(self, self->saddr, self->daddr); - - /* Make sure we have a hardware address before we return, - so DHCP clients gets happy */ - return wait_event_interruptible(self->open_wait, - !self->tsap_data->connected); -} - -/* - * Function irlan_eth_close (dev) - * - * Stop the ether network device, his function will usually be called by - * ifconfig down. We should now disconnect the link, We start the - * close timer, so that the instance will be removed if we are unable - * to discover the remote device after the disconnect. - */ -static int irlan_eth_close(struct net_device *dev) -{ - struct irlan_cb *self = netdev_priv(dev); - - /* Stop device */ - netif_stop_queue(dev); - - irlan_close_data_channel(self); - irlan_close_tsaps(self); - - irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); - irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); - - /* Remove frames queued on the control channel */ - skb_queue_purge(&self->client.txq); - - self->client.tx_busy = 0; - - return 0; -} - -/* - * Function irlan_eth_tx (skb) - * - * Transmits ethernet frames over IrDA link. - * - */ -static netdev_tx_t irlan_eth_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct irlan_cb *self = netdev_priv(dev); - int ret; - unsigned int len; - - /* skb headroom large enough to contain all IrDA-headers? */ - if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) { - struct sk_buff *new_skb = - skb_realloc_headroom(skb, self->max_header_size); - - /* We have to free the original skb anyway */ - dev_kfree_skb(skb); - - /* Did the realloc succeed? */ - if (new_skb == NULL) - return NETDEV_TX_OK; - - /* Use the new skb instead */ - skb = new_skb; - } - - netif_trans_update(dev); - - len = skb->len; - /* Now queue the packet in the transport layer */ - if (self->use_udata) - ret = irttp_udata_request(self->tsap_data, skb); - else - ret = irttp_data_request(self->tsap_data, skb); - - if (ret < 0) { - /* - * IrTTPs tx queue is full, so we just have to - * drop the frame! You might think that we should - * just return -1 and don't deallocate the frame, - * but that is dangerous since it's possible that - * we have replaced the original skb with a new - * one with larger headroom, and that would really - * confuse do_dev_queue_xmit() in dev.c! I have - * tried :-) DB - */ - /* irttp_data_request already free the packet */ - dev->stats.tx_dropped++; - } else { - dev->stats.tx_packets++; - dev->stats.tx_bytes += len; - } - - return NETDEV_TX_OK; -} - -/* - * Function irlan_eth_receive (handle, skb) - * - * This function gets the data that is received on the data channel - * - */ -int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb) -{ - struct irlan_cb *self = instance; - struct net_device *dev = self->dev; - - if (skb == NULL) { - dev->stats.rx_dropped++; - return 0; - } - if (skb->len < ETH_HLEN) { - pr_debug("%s() : IrLAN frame too short (%d)\n", - __func__, skb->len); - dev->stats.rx_dropped++; - dev_kfree_skb(skb); - return 0; - } - - /* - * Adopt this frame! Important to set all these fields since they - * might have been previously set by the low level IrDA network - * device driver - */ - skb->protocol = eth_type_trans(skb, dev); /* Remove eth header */ - - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - netif_rx(skb); /* Eat it! */ - - return 0; -} - -/* - * Function irlan_eth_flow (status) - * - * Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by - * controlling the queue stop/start. - * - * The IrDA link layer has the advantage to have flow control, and - * IrTTP now properly handles that. Flow controlling the higher layers - * prevent us to drop Tx packets in here (up to 15% for a TCP socket, - * more for UDP socket). - * Also, this allow us to reduce the overall transmit queue, which means - * less latency in case of mixed traffic. - * Jean II - */ -void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) -{ - struct irlan_cb *self; - struct net_device *dev; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - dev = self->dev; - - IRDA_ASSERT(dev != NULL, return;); - - pr_debug("%s() : flow %s ; running %d\n", __func__, - flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START", - netif_running(dev)); - - switch (flow) { - case FLOW_STOP: - /* IrTTP is full, stop higher layers */ - netif_stop_queue(dev); - break; - case FLOW_START: - default: - /* Tell upper layers that its time to transmit frames again */ - /* Schedule network layer */ - netif_wake_queue(dev); - break; - } -} - -/* - * Function set_multicast_list (dev) - * - * Configure the filtering of the device - * - */ -#define HW_MAX_ADDRS 4 /* Must query to get it! */ -static void irlan_eth_set_multicast_list(struct net_device *dev) -{ - struct irlan_cb *self = netdev_priv(dev); - - /* Check if data channel has been connected yet */ - if (self->client.state != IRLAN_DATA) { - pr_debug("%s(), delaying!\n", __func__); - return; - } - - if (dev->flags & IFF_PROMISC) { - /* Enable promiscuous mode */ - net_warn_ratelimited("Promiscuous mode not implemented by IrLAN!\n"); - } else if ((dev->flags & IFF_ALLMULTI) || - netdev_mc_count(dev) > HW_MAX_ADDRS) { - /* Disable promiscuous mode, use normal mode. */ - pr_debug("%s(), Setting multicast filter\n", __func__); - /* hardware_set_filter(NULL); */ - - irlan_set_multicast_filter(self, TRUE); - } else if (!netdev_mc_empty(dev)) { - pr_debug("%s(), Setting multicast filter\n", __func__); - /* Walk the address list, and load the filter */ - /* hardware_set_filter(dev->mc_list); */ - - irlan_set_multicast_filter(self, TRUE); - } else { - pr_debug("%s(), Clearing multicast filter\n", __func__); - irlan_set_multicast_filter(self, FALSE); - } - - if (dev->flags & IFF_BROADCAST) - irlan_set_broadcast_filter(self, TRUE); - else - irlan_set_broadcast_filter(self, FALSE); -} diff --git a/drivers/staging/irda/net/irlan/irlan_event.c b/drivers/staging/irda/net/irlan/irlan_event.c deleted file mode 100644 index 9a1cc11c16f6..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_event.c +++ /dev/null @@ -1,60 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_event.c - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Oct 20 09:10:16 1998 - * Modified at: Sat Oct 30 12:59:01 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <net/irda/irlan_event.h> - -const char * const irlan_state[] = { - "IRLAN_IDLE", - "IRLAN_QUERY", - "IRLAN_CONN", - "IRLAN_INFO", - "IRLAN_MEDIA", - "IRLAN_OPEN", - "IRLAN_WAIT", - "IRLAN_ARB", - "IRLAN_DATA", - "IRLAN_CLOSE", - "IRLAN_SYNC", -}; - -void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) -{ - pr_debug("%s(), %s\n", __func__ , irlan_state[state]); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - self->client.state = state; -} - -void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state) -{ - pr_debug("%s(), %s\n", __func__ , irlan_state[state]); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - self->provider.state = state; -} - diff --git a/drivers/staging/irda/net/irlan/irlan_filter.c b/drivers/staging/irda/net/irlan/irlan_filter.c deleted file mode 100644 index e755e90b2f26..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_filter.c +++ /dev/null @@ -1,240 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_filter.c - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri Jan 29 11:16:38 1999 - * Modified at: Sat Oct 30 12:58:45 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/skbuff.h> -#include <linux/random.h> -#include <linux/seq_file.h> - -#include <net/irda/irlan_common.h> -#include <net/irda/irlan_filter.h> - -/* - * Function irlan_filter_request (self, skb) - * - * Handle filter request from client peer device - * - */ -void irlan_filter_request(struct irlan_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - if ((self->provider.filter_type == IRLAN_DIRECTED) && - (self->provider.filter_operation == DYNAMIC)) - { - pr_debug("Giving peer a dynamic Ethernet address\n"); - self->provider.mac_address[0] = 0x40; - self->provider.mac_address[1] = 0x00; - self->provider.mac_address[2] = 0x00; - self->provider.mac_address[3] = 0x00; - - /* Use arbitration value to generate MAC address */ - if (self->provider.access_type == ACCESS_PEER) { - self->provider.mac_address[4] = - self->provider.send_arb_val & 0xff; - self->provider.mac_address[5] = - (self->provider.send_arb_val >> 8) & 0xff; - } else { - /* Just generate something for now */ - get_random_bytes(self->provider.mac_address+4, 1); - get_random_bytes(self->provider.mac_address+5, 1); - } - - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x03; - irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); - irlan_insert_short_param(skb, "MAX_ENTRY", 0x0001); - irlan_insert_array_param(skb, "FILTER_ENTRY", - self->provider.mac_address, 6); - return; - } - - if ((self->provider.filter_type == IRLAN_DIRECTED) && - (self->provider.filter_mode == FILTER)) - { - pr_debug("Directed filter on\n"); - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x00; - return; - } - if ((self->provider.filter_type == IRLAN_DIRECTED) && - (self->provider.filter_mode == NONE)) - { - pr_debug("Directed filter off\n"); - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x00; - return; - } - - if ((self->provider.filter_type == IRLAN_BROADCAST) && - (self->provider.filter_mode == FILTER)) - { - pr_debug("Broadcast filter on\n"); - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x00; - return; - } - if ((self->provider.filter_type == IRLAN_BROADCAST) && - (self->provider.filter_mode == NONE)) - { - pr_debug("Broadcast filter off\n"); - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x00; - return; - } - if ((self->provider.filter_type == IRLAN_MULTICAST) && - (self->provider.filter_mode == FILTER)) - { - pr_debug("Multicast filter on\n"); - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x00; - return; - } - if ((self->provider.filter_type == IRLAN_MULTICAST) && - (self->provider.filter_mode == NONE)) - { - pr_debug("Multicast filter off\n"); - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x00; - return; - } - if ((self->provider.filter_type == IRLAN_MULTICAST) && - (self->provider.filter_operation == GET)) - { - pr_debug("Multicast filter get\n"); - skb->data[0] = 0x00; /* Success? */ - skb->data[1] = 0x02; - irlan_insert_string_param(skb, "FILTER_MODE", "NONE"); - irlan_insert_short_param(skb, "MAX_ENTRY", 16); - return; - } - skb->data[0] = 0x00; /* Command not supported */ - skb->data[1] = 0x00; - - pr_debug("Not implemented!\n"); -} - -/* - * Function check_request_param (self, param, value) - * - * Check parameters in request from peer device - * - */ -void irlan_check_command_param(struct irlan_cb *self, char *param, char *value) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - pr_debug("%s, %s\n", param, value); - - /* - * This is experimental!! DB. - */ - if (strcmp(param, "MODE") == 0) { - self->use_udata = TRUE; - return; - } - - /* - * FILTER_TYPE - */ - if (strcmp(param, "FILTER_TYPE") == 0) { - if (strcmp(value, "DIRECTED") == 0) { - self->provider.filter_type = IRLAN_DIRECTED; - return; - } - if (strcmp(value, "MULTICAST") == 0) { - self->provider.filter_type = IRLAN_MULTICAST; - return; - } - if (strcmp(value, "BROADCAST") == 0) { - self->provider.filter_type = IRLAN_BROADCAST; - return; - } - } - /* - * FILTER_MODE - */ - if (strcmp(param, "FILTER_MODE") == 0) { - if (strcmp(value, "ALL") == 0) { - self->provider.filter_mode = ALL; - return; - } - if (strcmp(value, "FILTER") == 0) { - self->provider.filter_mode = FILTER; - return; - } - if (strcmp(value, "NONE") == 0) { - self->provider.filter_mode = FILTER; - return; - } - } - /* - * FILTER_OPERATION - */ - if (strcmp(param, "FILTER_OPERATION") == 0) { - if (strcmp(value, "DYNAMIC") == 0) { - self->provider.filter_operation = DYNAMIC; - return; - } - if (strcmp(value, "GET") == 0) { - self->provider.filter_operation = GET; - return; - } - } -} - -/* - * Function irlan_print_filter (filter_type, buf) - * - * Print status of filter. Used by /proc file system - * - */ -#ifdef CONFIG_PROC_FS -#define MASK2STR(m,s) { .mask = m, .str = s } - -void irlan_print_filter(struct seq_file *seq, int filter_type) -{ - static struct { - int mask; - const char *str; - } filter_mask2str[] = { - MASK2STR(IRLAN_DIRECTED, "DIRECTED"), - MASK2STR(IRLAN_FUNCTIONAL, "FUNCTIONAL"), - MASK2STR(IRLAN_GROUP, "GROUP"), - MASK2STR(IRLAN_MAC_FRAME, "MAC_FRAME"), - MASK2STR(IRLAN_MULTICAST, "MULTICAST"), - MASK2STR(IRLAN_BROADCAST, "BROADCAST"), - MASK2STR(IRLAN_IPX_SOCKET, "IPX_SOCKET"), - MASK2STR(0, NULL) - }, *p; - - for (p = filter_mask2str; p->str; p++) { - if (filter_type & p->mask) - seq_printf(seq, "%s ", p->str); - } - seq_putc(seq, '\n'); -} -#undef MASK2STR -#endif diff --git a/drivers/staging/irda/net/irlan/irlan_provider.c b/drivers/staging/irda/net/irlan/irlan_provider.c deleted file mode 100644 index 15c292cf2644..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_provider.c +++ /dev/null @@ -1,408 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_provider.c - * Version: 0.9 - * Description: IrDA LAN Access Protocol Implementation - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Sat Oct 30 12:52:10 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Sources: skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov> - * slip.c by Laurence Culhane, <loz@holmes.demon.co.uk> - * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/init.h> -#include <linux/random.h> -#include <linux/bitops.h> -#include <linux/slab.h> - -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/irttp.h> -#include <net/irda/irlmp.h> -#include <net/irda/irias_object.h> -#include <net/irda/iriap.h> -#include <net/irda/timer.h> - -#include <net/irda/irlan_common.h> -#include <net/irda/irlan_eth.h> -#include <net/irda/irlan_event.h> -#include <net/irda/irlan_provider.h> -#include <net/irda/irlan_filter.h> -#include <net/irda/irlan_client.h> - -static void irlan_provider_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb); - -/* - * Function irlan_provider_control_data_indication (handle, skb) - * - * This function gets the data that is received on the control channel - * - */ -static int irlan_provider_data_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct irlan_cb *self; - __u8 code; - - self = instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - - IRDA_ASSERT(skb != NULL, return -1;); - - code = skb->data[0]; - switch(code) { - case CMD_GET_PROVIDER_INFO: - pr_debug("Got GET_PROVIDER_INFO command!\n"); - irlan_do_provider_event(self, IRLAN_GET_INFO_CMD, skb); - break; - - case CMD_GET_MEDIA_CHAR: - pr_debug("Got GET_MEDIA_CHAR command!\n"); - irlan_do_provider_event(self, IRLAN_GET_MEDIA_CMD, skb); - break; - case CMD_OPEN_DATA_CHANNEL: - pr_debug("Got OPEN_DATA_CHANNEL command!\n"); - irlan_do_provider_event(self, IRLAN_OPEN_DATA_CMD, skb); - break; - case CMD_FILTER_OPERATION: - pr_debug("Got FILTER_OPERATION command!\n"); - irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb); - break; - case CMD_RECONNECT_DATA_CHAN: - pr_debug("%s(), Got RECONNECT_DATA_CHAN command\n", __func__); - pr_debug("%s(), NOT IMPLEMENTED\n", __func__); - break; - case CMD_CLOSE_DATA_CHAN: - pr_debug("Got CLOSE_DATA_CHAN command!\n"); - pr_debug("%s(), NOT IMPLEMENTED\n", __func__); - break; - default: - pr_debug("%s(), Unknown command!\n", __func__); - break; - } - return 0; -} - -/* - * Function irlan_provider_connect_indication (handle, skb, priv) - * - * Got connection from peer IrLAN client - * - */ -static void irlan_provider_connect_indication(void *instance, void *sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - struct irlan_cb *self; - struct tsap_cb *tsap; - - self = instance; - tsap = sap; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - IRDA_ASSERT(tsap == self->provider.tsap_ctrl,return;); - IRDA_ASSERT(self->provider.state == IRLAN_IDLE, return;); - - self->provider.max_sdu_size = max_sdu_size; - self->provider.max_header_size = max_header_size; - - irlan_do_provider_event(self, IRLAN_CONNECT_INDICATION, NULL); - - /* - * If we are in peer mode, the client may not have got the discovery - * indication it needs to make progress. If the client is still in - * IDLE state, we must kick it. - */ - if ((self->provider.access_type == ACCESS_PEER) && - (self->client.state == IRLAN_IDLE)) - { - irlan_client_wakeup(self, self->saddr, self->daddr); - } -} - -/* - * Function irlan_provider_connect_response (handle) - * - * Accept incoming connection - * - */ -void irlan_provider_connect_response(struct irlan_cb *self, - struct tsap_cb *tsap) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - /* Just accept */ - irttp_connect_response(tsap, IRLAN_MTU, NULL); -} - -static void irlan_provider_disconnect_indication(void *instance, void *sap, - LM_REASON reason, - struct sk_buff *userdata) -{ - struct irlan_cb *self; - struct tsap_cb *tsap; - - pr_debug("%s(), reason=%d\n", __func__ , reason); - - self = instance; - tsap = sap; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - IRDA_ASSERT(tsap != NULL, return;); - IRDA_ASSERT(tsap->magic == TTP_TSAP_MAGIC, return;); - - IRDA_ASSERT(tsap == self->provider.tsap_ctrl, return;); - - irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); -} - -/* - * Function irlan_parse_open_data_cmd (self, skb) - * - * - * - */ -int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb) -{ - int ret; - - ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb); - - /* Open data channel */ - irlan_open_data_tsap(self); - - return ret; -} - -/* - * Function parse_command (skb) - * - * Extract all parameters from received buffer, then feed them to - * check_params for parsing - * - */ -int irlan_provider_parse_command(struct irlan_cb *self, int cmd, - struct sk_buff *skb) -{ - __u8 *frame; - __u8 *ptr; - int count; - __u16 val_len; - int i; - char *name; - char *value; - int ret = RSP_SUCCESS; - - IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;); - - pr_debug("%s(), skb->len=%d\n", __func__ , (int)skb->len); - - IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;); - - if (!skb) - return -RSP_PROTOCOL_ERROR; - - frame = skb->data; - - name = kmalloc(255, GFP_ATOMIC); - if (!name) - return -RSP_INSUFFICIENT_RESOURCES; - value = kmalloc(1016, GFP_ATOMIC); - if (!value) { - kfree(name); - return -RSP_INSUFFICIENT_RESOURCES; - } - - /* How many parameters? */ - count = frame[1]; - - pr_debug("Got %d parameters\n", count); - - ptr = frame+2; - - /* For all parameters */ - for (i=0; i<count;i++) { - ret = irlan_extract_param(ptr, name, value, &val_len); - if (ret < 0) { - pr_debug("%s(), IrLAN, Error!\n", __func__); - break; - } - ptr+=ret; - ret = RSP_SUCCESS; - irlan_check_command_param(self, name, value); - } - /* Cleanup */ - kfree(name); - kfree(value); - - return ret; -} - -/* - * Function irlan_provider_send_reply (self, info) - * - * Send reply to query to peer IrLAN layer - * - */ -void irlan_provider_send_reply(struct irlan_cb *self, int command, - int ret_code) -{ - struct sk_buff *skb; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); - - skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER + - /* Bigger param length comes from CMD_GET_MEDIA_CHAR */ - IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") + - IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") + - IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") + - IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "HOSTED"), - GFP_ATOMIC); - - if (!skb) - return; - - /* Reserve space for TTP, LMP, and LAP header */ - skb_reserve(skb, self->provider.max_header_size); - skb_put(skb, 2); - - switch (command) { - case CMD_GET_PROVIDER_INFO: - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x02; /* 2 parameters */ - switch (self->media) { - case MEDIA_802_3: - irlan_insert_string_param(skb, "MEDIA", "802.3"); - break; - case MEDIA_802_5: - irlan_insert_string_param(skb, "MEDIA", "802.5"); - break; - default: - pr_debug("%s(), unknown media type!\n", __func__); - break; - } - irlan_insert_short_param(skb, "IRLAN_VER", 0x0101); - break; - - case CMD_GET_MEDIA_CHAR: - skb->data[0] = 0x00; /* Success */ - skb->data[1] = 0x05; /* 5 parameters */ - irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED"); - irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST"); - irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST"); - - switch (self->provider.access_type) { - case ACCESS_DIRECT: - irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT"); - break; - case ACCESS_PEER: - irlan_insert_string_param(skb, "ACCESS_TYPE", "PEER"); - break; - case ACCESS_HOSTED: - irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED"); - break; - default: - pr_debug("%s(), Unknown access type\n", __func__); - break; - } - irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee); - break; - case CMD_OPEN_DATA_CHANNEL: - skb->data[0] = 0x00; /* Success */ - if (self->provider.send_arb_val) { - skb->data[1] = 0x03; /* 3 parameters */ - irlan_insert_short_param(skb, "CON_ARB", - self->provider.send_arb_val); - } else - skb->data[1] = 0x02; /* 2 parameters */ - irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data); - irlan_insert_string_param(skb, "RECONNECT_KEY", "LINUX RULES!"); - break; - case CMD_FILTER_OPERATION: - irlan_filter_request(self, skb); - break; - default: - pr_debug("%s(), Unknown command!\n", __func__); - break; - } - - irttp_data_request(self->provider.tsap_ctrl, skb); -} - -/* - * Function irlan_provider_register(void) - * - * Register provider support so we can accept incoming connections. - * - */ -int irlan_provider_open_ctrl_tsap(struct irlan_cb *self) -{ - struct tsap_cb *tsap; - notify_t notify; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - - /* Check if already open */ - if (self->provider.tsap_ctrl) - return -1; - - /* - * First register well known control TSAP - */ - irda_notify_init(¬ify); - notify.data_indication = irlan_provider_data_indication; - notify.connect_indication = irlan_provider_connect_indication; - notify.disconnect_indication = irlan_provider_disconnect_indication; - notify.instance = self; - strlcpy(notify.name, "IrLAN ctrl (p)", sizeof(notify.name)); - - tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify); - if (!tsap) { - pr_debug("%s(), Got no tsap!\n", __func__); - return -1; - } - self->provider.tsap_ctrl = tsap; - - /* Register with LM-IAS */ - irlan_ias_register(self, tsap->stsap_sel); - - return 0; -} - diff --git a/drivers/staging/irda/net/irlan/irlan_provider_event.c b/drivers/staging/irda/net/irlan/irlan_provider_event.c deleted file mode 100644 index 9c4f7f51d6b5..000000000000 --- a/drivers/staging/irda/net/irlan/irlan_provider_event.c +++ /dev/null @@ -1,233 +0,0 @@ -/********************************************************************* - * - * Filename: irlan_provider_event.c - * Version: 0.9 - * Description: IrLAN provider state machine) - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Sat Oct 30 12:52:41 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <net/irda/irda.h> -#include <net/irda/iriap.h> -#include <net/irda/irlmp.h> -#include <net/irda/irttp.h> - -#include <net/irda/irlan_provider.h> -#include <net/irda/irlan_event.h> - -static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); -static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb); - -static int (*state[])(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) = -{ - irlan_provider_state_idle, - NULL, /* Query */ - NULL, /* Info */ - irlan_provider_state_info, - NULL, /* Media */ - irlan_provider_state_open, - NULL, /* Wait */ - NULL, /* Arb */ - irlan_provider_state_data, - NULL, /* Close */ - NULL, /* Sync */ -}; - -void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(*state[ self->provider.state] != NULL, return;); - - (*state[self->provider.state]) (self, event, skb); -} - -/* - * Function irlan_provider_state_idle (event, skb, info) - * - * IDLE, We are waiting for an indication that there is a provider - * available. - */ -static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - - switch(event) { - case IRLAN_CONNECT_INDICATION: - irlan_provider_connect_response( self, self->provider.tsap_ctrl); - irlan_next_provider_state( self, IRLAN_INFO); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_provider_state_info (self, event, skb, info) - * - * INFO, We have issued a GetInfo command and is awaiting a reply. - */ -static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - - switch(event) { - case IRLAN_GET_INFO_CMD: - /* Be sure to use 802.3 in case of peer mode */ - if (self->provider.access_type == ACCESS_PEER) { - self->media = MEDIA_802_3; - - /* Check if client has started yet */ - if (self->client.state == IRLAN_IDLE) { - /* This should get the client going */ - irlmp_discovery_request(8); - } - } - - irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO, - RSP_SUCCESS); - /* Keep state */ - break; - case IRLAN_GET_MEDIA_CMD: - irlan_provider_send_reply(self, CMD_GET_MEDIA_CHAR, - RSP_SUCCESS); - /* Keep state */ - break; - case IRLAN_OPEN_DATA_CMD: - ret = irlan_parse_open_data_cmd(self, skb); - if (self->provider.access_type == ACCESS_PEER) { - /* FIXME: make use of random functions! */ - self->provider.send_arb_val = (jiffies & 0xffff); - } - irlan_provider_send_reply(self, CMD_OPEN_DATA_CHANNEL, ret); - - if (ret == RSP_SUCCESS) { - irlan_next_provider_state(self, IRLAN_OPEN); - - /* Signal client that we are now open */ - irlan_do_client_event(self, IRLAN_PROVIDER_SIGNAL, NULL); - } - break; - case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ - case IRLAN_LAP_DISCONNECT: - irlan_next_provider_state(self, IRLAN_IDLE); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_provider_state_open (self, event, skb, info) - * - * OPEN, The client has issued a OpenData command and is awaiting a - * reply - * - */ -static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - - switch(event) { - case IRLAN_FILTER_CONFIG_CMD: - irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); - irlan_provider_send_reply(self, CMD_FILTER_OPERATION, - RSP_SUCCESS); - /* Keep state */ - break; - case IRLAN_DATA_CONNECT_INDICATION: - irlan_next_provider_state(self, IRLAN_DATA); - irlan_provider_connect_response(self, self->tsap_data); - break; - case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ - case IRLAN_LAP_DISCONNECT: - irlan_next_provider_state(self, IRLAN_IDLE); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irlan_provider_state_data (self, event, skb, info) - * - * DATA, The data channel is connected, allowing data transfers between - * the local and remote machines. - * - */ -static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); - - switch(event) { - case IRLAN_FILTER_CONFIG_CMD: - irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); - irlan_provider_send_reply(self, CMD_FILTER_OPERATION, - RSP_SUCCESS); - break; - case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ - case IRLAN_LAP_DISCONNECT: - irlan_next_provider_state(self, IRLAN_IDLE); - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__ , event); - break; - } - if (skb) - dev_kfree_skb(skb); - - return 0; -} - - - - - - - - - - diff --git a/drivers/staging/irda/net/irlap.c b/drivers/staging/irda/net/irlap.c deleted file mode 100644 index d7d894423b4f..000000000000 --- a/drivers/staging/irda/net/irlap.c +++ /dev/null @@ -1,1207 +0,0 @@ -/********************************************************************* - * - * Filename: irlap.c - * Version: 1.0 - * Description: IrLAP implementation for Linux - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Tue Dec 14 09:26:44 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/random.h> -#include <linux/module.h> -#include <linux/seq_file.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> -#include <net/irda/irqueue.h> -#include <net/irda/irlmp.h> -#include <net/irda/irlmp_frame.h> -#include <net/irda/irlap_frame.h> -#include <net/irda/irlap.h> -#include <net/irda/timer.h> -#include <net/irda/qos.h> - -static hashbin_t *irlap = NULL; -int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ; - -/* This is the delay of missed pf period before generating an event - * to the application. The spec mandate 3 seconds, but in some cases - * it's way too long. - Jean II */ -int sysctl_warn_noreply_time = 3; - -extern void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb); -static void __irlap_close(struct irlap_cb *self); -static void irlap_init_qos_capabilities(struct irlap_cb *self, - struct qos_info *qos_user); - -static const char *const lap_reasons[] __maybe_unused = { - "ERROR, NOT USED", - "LAP_DISC_INDICATION", - "LAP_NO_RESPONSE", - "LAP_RESET_INDICATION", - "LAP_FOUND_NONE", - "LAP_MEDIA_BUSY", - "LAP_PRIMARY_CONFLICT", - "ERROR, NOT USED", -}; - -int __init irlap_init(void) -{ - /* Check if the compiler did its job properly. - * May happen on some ARM configuration, check with Russell King. */ - IRDA_ASSERT(sizeof(struct xid_frame) == 14, ;); - IRDA_ASSERT(sizeof(struct test_frame) == 10, ;); - IRDA_ASSERT(sizeof(struct ua_frame) == 10, ;); - IRDA_ASSERT(sizeof(struct snrm_frame) == 11, ;); - - /* Allocate master array */ - irlap = hashbin_new(HB_LOCK); - if (irlap == NULL) { - net_err_ratelimited("%s: can't allocate irlap hashbin!\n", - __func__); - return -ENOMEM; - } - - return 0; -} - -void irlap_cleanup(void) -{ - IRDA_ASSERT(irlap != NULL, return;); - - hashbin_delete(irlap, (FREE_FUNC) __irlap_close); -} - -/* - * Function irlap_open (driver) - * - * Initialize IrLAP layer - * - */ -struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, - const char *hw_name) -{ - struct irlap_cb *self; - - /* Initialize the irlap structure. */ - self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL); - if (self == NULL) - return NULL; - - self->magic = LAP_MAGIC; - - /* Make a binding between the layers */ - self->netdev = dev; - self->qos_dev = qos; - /* Copy hardware name */ - if(hw_name != NULL) { - strlcpy(self->hw_name, hw_name, sizeof(self->hw_name)); - } else { - self->hw_name[0] = '\0'; - } - - /* FIXME: should we get our own field? */ - dev->atalk_ptr = self; - - self->state = LAP_OFFLINE; - - /* Initialize transmit queue */ - skb_queue_head_init(&self->txq); - skb_queue_head_init(&self->txq_ultra); - skb_queue_head_init(&self->wx_list); - - /* My unique IrLAP device address! */ - /* We don't want the broadcast address, neither the NULL address - * (most often used to signify "invalid"), and we don't want an - * address already in use (otherwise connect won't be able - * to select the proper link). - Jean II */ - do { - get_random_bytes(&self->saddr, sizeof(self->saddr)); - } while ((self->saddr == 0x0) || (self->saddr == BROADCAST) || - (hashbin_lock_find(irlap, self->saddr, NULL)) ); - /* Copy to the driver */ - memcpy(dev->dev_addr, &self->saddr, 4); - - timer_setup(&self->slot_timer, NULL, 0); - timer_setup(&self->query_timer, NULL, 0); - timer_setup(&self->discovery_timer, NULL, 0); - timer_setup(&self->final_timer, NULL, 0); - timer_setup(&self->poll_timer, NULL, 0); - timer_setup(&self->wd_timer, NULL, 0); - timer_setup(&self->backoff_timer, NULL, 0); - timer_setup(&self->media_busy_timer, NULL, 0); - - irlap_apply_default_connection_parameters(self); - - self->N3 = 3; /* # connections attempts to try before giving up */ - - self->state = LAP_NDM; - - hashbin_insert(irlap, (irda_queue_t *) self, self->saddr, NULL); - - irlmp_register_link(self, self->saddr, &self->notify); - - return self; -} -EXPORT_SYMBOL(irlap_open); - -/* - * Function __irlap_close (self) - * - * Remove IrLAP and all allocated memory. Stop any pending timers. - * - */ -static void __irlap_close(struct irlap_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Stop timers */ - del_timer(&self->slot_timer); - del_timer(&self->query_timer); - del_timer(&self->discovery_timer); - del_timer(&self->final_timer); - del_timer(&self->poll_timer); - del_timer(&self->wd_timer); - del_timer(&self->backoff_timer); - del_timer(&self->media_busy_timer); - - irlap_flush_all_queues(self); - - self->magic = 0; - - kfree(self); -} - -/* - * Function irlap_close (self) - * - * Remove IrLAP instance - * - */ -void irlap_close(struct irlap_cb *self) -{ - struct irlap_cb *lap; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* We used to send a LAP_DISC_INDICATION here, but this was - * racy. This has been move within irlmp_unregister_link() - * itself. Jean II */ - - /* Kill the LAP and all LSAPs on top of it */ - irlmp_unregister_link(self->saddr); - self->notify.instance = NULL; - - /* Be sure that we manage to remove ourself from the hash */ - lap = hashbin_remove(irlap, self->saddr, NULL); - if (!lap) { - pr_debug("%s(), Didn't find myself!\n", __func__); - return; - } - __irlap_close(lap); -} -EXPORT_SYMBOL(irlap_close); - -/* - * Function irlap_connect_indication (self, skb) - * - * Another device is attempting to make a connection - * - */ -void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_init_qos_capabilities(self, NULL); /* No user QoS! */ - - irlmp_link_connect_indication(self->notify.instance, self->saddr, - self->daddr, &self->qos_tx, skb); -} - -/* - * Function irlap_connect_response (self, skb) - * - * Service user has accepted incoming connection - * - */ -void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata) -{ - irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL); -} - -/* - * Function irlap_connect_request (self, daddr, qos_user, sniff) - * - * Request connection with another device, sniffing is not implemented - * yet. - * - */ -void irlap_connect_request(struct irlap_cb *self, __u32 daddr, - struct qos_info *qos_user, int sniff) -{ - pr_debug("%s(), daddr=0x%08x\n", __func__, daddr); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - self->daddr = daddr; - - /* - * If the service user specifies QoS values for this connection, - * then use them - */ - irlap_init_qos_capabilities(self, qos_user); - - if ((self->state == LAP_NDM) && !self->media_busy) - irlap_do_event(self, CONNECT_REQUEST, NULL, NULL); - else - self->connect_pending = TRUE; -} - -/* - * Function irlap_connect_confirm (self, skb) - * - * Connection request has been accepted - * - */ -void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlmp_link_connect_confirm(self->notify.instance, &self->qos_tx, skb); -} - -/* - * Function irlap_data_indication (self, skb) - * - * Received data frames from IR-port, so we just pass them up to - * IrLMP for further processing - * - */ -void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb, - int unreliable) -{ - /* Hide LAP header from IrLMP layer */ - skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); - - irlmp_link_data_indication(self->notify.instance, skb, unreliable); -} - - -/* - * Function irlap_data_request (self, skb) - * - * Queue data for transmission, must wait until XMIT state - * - */ -void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, - int unreliable) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), - return;); - skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); - - /* - * Must set frame format now so that the rest of the code knows - * if its dealing with an I or an UI frame - */ - if (unreliable) - skb->data[1] = UI_FRAME; - else - skb->data[1] = I_FRAME; - - /* Don't forget to refcount it - see irlmp_connect_request(). */ - skb_get(skb); - - /* Add at the end of the queue (keep ordering) - Jean II */ - skb_queue_tail(&self->txq, skb); - - /* - * Send event if this frame only if we are in the right state - * FIXME: udata should be sent first! (skb_queue_head?) - */ - if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) { - /* If we are not already processing the Tx queue, trigger - * transmission immediately - Jean II */ - if((skb_queue_len(&self->txq) <= 1) && (!self->local_busy)) - irlap_do_event(self, DATA_REQUEST, skb, NULL); - /* Otherwise, the packets will be sent normally at the - * next pf-poll - Jean II */ - } -} - -/* - * Function irlap_unitdata_request (self, skb) - * - * Send Ultra data. This is data that must be sent outside any connection - * - */ -#ifdef CONFIG_IRDA_ULTRA -void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), - return;); - skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); - - skb->data[0] = CBROADCAST; - skb->data[1] = UI_FRAME; - - /* Don't need to refcount, see irlmp_connless_data_request() */ - - skb_queue_tail(&self->txq_ultra, skb); - - irlap_do_event(self, SEND_UI_FRAME, NULL, NULL); -} -#endif /*CONFIG_IRDA_ULTRA */ - -/* - * Function irlap_udata_indication (self, skb) - * - * Receive Ultra data. This is data that is received outside any connection - * - */ -#ifdef CONFIG_IRDA_ULTRA -void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - /* Hide LAP header from IrLMP layer */ - skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); - - irlmp_link_unitdata_indication(self->notify.instance, skb); -} -#endif /* CONFIG_IRDA_ULTRA */ - -/* - * Function irlap_disconnect_request (void) - * - * Request to disconnect connection by service user - */ -void irlap_disconnect_request(struct irlap_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Don't disconnect until all data frames are successfully sent */ - if (!skb_queue_empty(&self->txq)) { - self->disconnect_pending = TRUE; - return; - } - - /* Check if we are in the right state for disconnecting */ - switch (self->state) { - case LAP_XMIT_P: /* FALLTHROUGH */ - case LAP_XMIT_S: /* FALLTHROUGH */ - case LAP_CONN: /* FALLTHROUGH */ - case LAP_RESET_WAIT: /* FALLTHROUGH */ - case LAP_RESET_CHECK: - irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL); - break; - default: - pr_debug("%s(), disconnect pending!\n", __func__); - self->disconnect_pending = TRUE; - break; - } -} - -/* - * Function irlap_disconnect_indication (void) - * - * Disconnect request from other device - * - */ -void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) -{ - pr_debug("%s(), reason=%s\n", __func__, lap_reasons[reason]); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Flush queues */ - irlap_flush_all_queues(self); - - switch (reason) { - case LAP_RESET_INDICATION: - pr_debug("%s(), Sending reset request!\n", __func__); - irlap_do_event(self, RESET_REQUEST, NULL, NULL); - break; - case LAP_NO_RESPONSE: /* FALLTHROUGH */ - case LAP_DISC_INDICATION: /* FALLTHROUGH */ - case LAP_FOUND_NONE: /* FALLTHROUGH */ - case LAP_MEDIA_BUSY: - irlmp_link_disconnect_indication(self->notify.instance, self, - reason, NULL); - break; - default: - net_err_ratelimited("%s: Unknown reason %d\n", - __func__, reason); - } -} - -/* - * Function irlap_discovery_request (gen_addr_bit) - * - * Start one single discovery operation. - * - */ -void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery) -{ - struct irlap_info info; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(discovery != NULL, return;); - - pr_debug("%s(), nslots = %d\n", __func__, discovery->nslots); - - IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) || - (discovery->nslots == 8) || (discovery->nslots == 16), - return;); - - /* Discovery is only possible in NDM mode */ - if (self->state != LAP_NDM) { - pr_debug("%s(), discovery only possible in NDM mode\n", - __func__); - irlap_discovery_confirm(self, NULL); - /* Note : in theory, if we are not in NDM, we could postpone - * the discovery like we do for connection request. - * In practice, it's not worth it. If the media was busy, - * it's likely next time around it won't be busy. If we are - * in REPLY state, we will get passive discovery info & event. - * Jean II */ - return; - } - - /* Check if last discovery request finished in time, or if - * it was aborted due to the media busy flag. */ - if (self->discovery_log != NULL) { - hashbin_delete(self->discovery_log, (FREE_FUNC) kfree); - self->discovery_log = NULL; - } - - /* All operations will occur at predictable time, no need to lock */ - self->discovery_log = hashbin_new(HB_NOLOCK); - - if (self->discovery_log == NULL) { - net_warn_ratelimited("%s(), Unable to allocate discovery log!\n", - __func__); - return; - } - - info.S = discovery->nslots; /* Number of slots */ - info.s = 0; /* Current slot */ - - self->discovery_cmd = discovery; - info.discovery = discovery; - - /* sysctl_slot_timeout bounds are checked in irsysctl.c - Jean II */ - self->slot_timeout = msecs_to_jiffies(sysctl_slot_timeout); - - irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info); -} - -/* - * Function irlap_discovery_confirm (log) - * - * A device has been discovered in front of this station, we - * report directly to LMP. - */ -void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - IRDA_ASSERT(self->notify.instance != NULL, return;); - - /* - * Check for successful discovery, since we are then allowed to clear - * the media busy condition (IrLAP 6.13.4 - p.94). This should allow - * us to make connection attempts much faster and easier (i.e. no - * collisions). - * Setting media busy to false will also generate an event allowing - * to process pending events in NDM state machine. - * Note : the spec doesn't define what's a successful discovery is. - * If we want Ultra to work, it's successful even if there is - * nobody discovered - Jean II - */ - if (discovery_log) - irda_device_set_media_busy(self->netdev, FALSE); - - /* Inform IrLMP */ - irlmp_link_discovery_confirm(self->notify.instance, discovery_log); -} - -/* - * Function irlap_discovery_indication (log) - * - * Somebody is trying to discover us! - * - */ -void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(discovery != NULL, return;); - - IRDA_ASSERT(self->notify.instance != NULL, return;); - - /* A device is very likely to connect immediately after it performs - * a successful discovery. This means that in our case, we are much - * more likely to receive a connection request over the medium. - * So, we backoff to avoid collisions. - * IrLAP spec 6.13.4 suggest 100ms... - * Note : this little trick actually make a *BIG* difference. If I set - * my Linux box with discovery enabled and one Ultra frame sent every - * second, my Palm has no trouble connecting to it every time ! - * Jean II */ - irda_device_set_media_busy(self->netdev, SMALL); - - irlmp_link_discovery_indication(self->notify.instance, discovery); -} - -/* - * Function irlap_status_indication (quality_of_link) - */ -void irlap_status_indication(struct irlap_cb *self, int quality_of_link) -{ - switch (quality_of_link) { - case STATUS_NO_ACTIVITY: - net_info_ratelimited("IrLAP, no activity on link!\n"); - break; - case STATUS_NOISY: - net_info_ratelimited("IrLAP, noisy link!\n"); - break; - default: - break; - } - irlmp_status_indication(self->notify.instance, - quality_of_link, LOCK_NO_CHANGE); -} - -/* - * Function irlap_reset_indication (void) - */ -void irlap_reset_indication(struct irlap_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - if (self->state == LAP_RESET_WAIT) - irlap_do_event(self, RESET_REQUEST, NULL, NULL); - else - irlap_do_event(self, RESET_RESPONSE, NULL, NULL); -} - -/* - * Function irlap_reset_confirm (void) - */ -void irlap_reset_confirm(void) -{ -} - -/* - * Function irlap_generate_rand_time_slot (S, s) - * - * Generate a random time slot between s and S-1 where - * S = Number of slots (0 -> S-1) - * s = Current slot - */ -int irlap_generate_rand_time_slot(int S, int s) -{ - static int rand; - int slot; - - IRDA_ASSERT((S - s) > 0, return 0;); - - rand += jiffies; - rand ^= (rand << 12); - rand ^= (rand >> 20); - - slot = s + rand % (S-s); - - IRDA_ASSERT((slot >= s) || (slot < S), return 0;); - - return slot; -} - -/* - * Function irlap_update_nr_received (nr) - * - * Remove all acknowledged frames in current window queue. This code is - * not intuitive and you should not try to change it. If you think it - * contains bugs, please mail a patch to the author instead. - */ -void irlap_update_nr_received(struct irlap_cb *self, int nr) -{ - struct sk_buff *skb = NULL; - int count = 0; - - /* - * Remove all the ack-ed frames from the window queue. - */ - - /* - * Optimize for the common case. It is most likely that the receiver - * will acknowledge all the frames we have sent! So in that case we - * delete all frames stored in window. - */ - if (nr == self->vs) { - while ((skb = skb_dequeue(&self->wx_list)) != NULL) { - dev_kfree_skb(skb); - } - /* The last acked frame is the next to send minus one */ - self->va = nr - 1; - } else { - /* Remove all acknowledged frames in current window */ - while ((skb_peek(&self->wx_list) != NULL) && - (((self->va+1) % 8) != nr)) - { - skb = skb_dequeue(&self->wx_list); - dev_kfree_skb(skb); - - self->va = (self->va + 1) % 8; - count++; - } - } - - /* Advance window */ - self->window = self->window_size - skb_queue_len(&self->wx_list); -} - -/* - * Function irlap_validate_ns_received (ns) - * - * Validate the next to send (ns) field from received frame. - */ -int irlap_validate_ns_received(struct irlap_cb *self, int ns) -{ - /* ns as expected? */ - if (ns == self->vr) - return NS_EXPECTED; - /* - * Stations are allowed to treat invalid NS as unexpected NS - * IrLAP, Recv ... with-invalid-Ns. p. 84 - */ - return NS_UNEXPECTED; - - /* return NR_INVALID; */ -} -/* - * Function irlap_validate_nr_received (nr) - * - * Validate the next to receive (nr) field from received frame. - * - */ -int irlap_validate_nr_received(struct irlap_cb *self, int nr) -{ - /* nr as expected? */ - if (nr == self->vs) { - pr_debug("%s(), expected!\n", __func__); - return NR_EXPECTED; - } - - /* - * unexpected nr? (but within current window), first we check if the - * ns numbers of the frames in the current window wrap. - */ - if (self->va < self->vs) { - if ((nr >= self->va) && (nr <= self->vs)) - return NR_UNEXPECTED; - } else { - if ((nr >= self->va) || (nr <= self->vs)) - return NR_UNEXPECTED; - } - - /* Invalid nr! */ - return NR_INVALID; -} - -/* - * Function irlap_initiate_connection_state () - * - * Initialize the connection state parameters - * - */ -void irlap_initiate_connection_state(struct irlap_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Next to send and next to receive */ - self->vs = self->vr = 0; - - /* Last frame which got acked (0 - 1) % 8 */ - self->va = 7; - - self->window = 1; - - self->remote_busy = FALSE; - self->retry_count = 0; -} - -/* - * Function irlap_wait_min_turn_around (self, qos) - * - * Wait negotiated minimum turn around time, this function actually sets - * the number of BOS's that must be sent before the next transmitted - * frame in order to delay for the specified amount of time. This is - * done to avoid using timers, and the forbidden udelay! - */ -void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos) -{ - __u32 min_turn_time; - __u32 speed; - - /* Get QoS values. */ - speed = qos->baud_rate.value; - min_turn_time = qos->min_turn_time.value; - - /* No need to calculate XBOFs for speeds over 115200 bps */ - if (speed > 115200) { - self->mtt_required = min_turn_time; - return; - } - - /* - * Send additional BOF's for the next frame for the requested - * min turn time, so now we must calculate how many chars (XBOF's) we - * must send for the requested time period (min turn time) - */ - self->xbofs_delay = irlap_min_turn_time_in_bytes(speed, min_turn_time); -} - -/* - * Function irlap_flush_all_queues (void) - * - * Flush all queues - * - */ -void irlap_flush_all_queues(struct irlap_cb *self) -{ - struct sk_buff* skb; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Free transmission queue */ - while ((skb = skb_dequeue(&self->txq)) != NULL) - dev_kfree_skb(skb); - - while ((skb = skb_dequeue(&self->txq_ultra)) != NULL) - dev_kfree_skb(skb); - - /* Free sliding window buffered packets */ - while ((skb = skb_dequeue(&self->wx_list)) != NULL) - dev_kfree_skb(skb); -} - -/* - * Function irlap_setspeed (self, speed) - * - * Change the speed of the IrDA port - * - */ -static void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now) -{ - struct sk_buff *skb; - - pr_debug("%s(), setting speed to %d\n", __func__, speed); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - self->speed = speed; - - /* Change speed now, or just piggyback speed on frames */ - if (now) { - /* Send down empty frame to trigger speed change */ - skb = alloc_skb(0, GFP_ATOMIC); - if (skb) - irlap_queue_xmit(self, skb); - } -} - -/* - * Function irlap_init_qos_capabilities (self, qos) - * - * Initialize QoS for this IrLAP session, What we do is to compute the - * intersection of the QoS capabilities for the user, driver and for - * IrLAP itself. Normally, IrLAP will not specify any values, but it can - * be used to restrict certain values. - */ -static void irlap_init_qos_capabilities(struct irlap_cb *self, - struct qos_info *qos_user) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(self->netdev != NULL, return;); - - /* Start out with the maximum QoS support possible */ - irda_init_max_qos_capabilies(&self->qos_rx); - - /* Apply drivers QoS capabilities */ - irda_qos_compute_intersection(&self->qos_rx, self->qos_dev); - - /* - * Check for user supplied QoS parameters. The service user is only - * allowed to supply these values. We check each parameter since the - * user may not have set all of them. - */ - if (qos_user) { - pr_debug("%s(), Found user specified QoS!\n", __func__); - - if (qos_user->baud_rate.bits) - self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits; - - if (qos_user->max_turn_time.bits) - self->qos_rx.max_turn_time.bits &= qos_user->max_turn_time.bits; - if (qos_user->data_size.bits) - self->qos_rx.data_size.bits &= qos_user->data_size.bits; - - if (qos_user->link_disc_time.bits) - self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits; - } - - /* Use 500ms in IrLAP for now */ - self->qos_rx.max_turn_time.bits &= 0x01; - - /* Set data size */ - /*self->qos_rx.data_size.bits &= 0x03;*/ - - irda_qos_bits_to_value(&self->qos_rx); -} - -/* - * Function irlap_apply_default_connection_parameters (void, now) - * - * Use the default connection and transmission parameters - */ -void irlap_apply_default_connection_parameters(struct irlap_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* xbofs : Default value in NDM */ - self->next_bofs = 12; - self->bofs_count = 12; - - /* NDM Speed is 9600 */ - irlap_change_speed(self, 9600, TRUE); - - /* Set mbusy when going to NDM state */ - irda_device_set_media_busy(self->netdev, TRUE); - - /* - * Generate random connection address for this session, which must - * be 7 bits wide and different from 0x00 and 0xfe - */ - while ((self->caddr == 0x00) || (self->caddr == 0xfe)) { - get_random_bytes(&self->caddr, sizeof(self->caddr)); - self->caddr &= 0xfe; - } - - /* Use default values until connection has been negitiated */ - self->slot_timeout = sysctl_slot_timeout; - self->final_timeout = FINAL_TIMEOUT; - self->poll_timeout = POLL_TIMEOUT; - self->wd_timeout = WD_TIMEOUT; - - /* Set some default values */ - self->qos_tx.baud_rate.value = 9600; - self->qos_rx.baud_rate.value = 9600; - self->qos_tx.max_turn_time.value = 0; - self->qos_rx.max_turn_time.value = 0; - self->qos_tx.min_turn_time.value = 0; - self->qos_rx.min_turn_time.value = 0; - self->qos_tx.data_size.value = 64; - self->qos_rx.data_size.value = 64; - self->qos_tx.window_size.value = 1; - self->qos_rx.window_size.value = 1; - self->qos_tx.additional_bofs.value = 12; - self->qos_rx.additional_bofs.value = 12; - self->qos_tx.link_disc_time.value = 0; - self->qos_rx.link_disc_time.value = 0; - - irlap_flush_all_queues(self); - - self->disconnect_pending = FALSE; - self->connect_pending = FALSE; -} - -/* - * Function irlap_apply_connection_parameters (qos, now) - * - * Initialize IrLAP with the negotiated QoS values - * - * If 'now' is false, the speed and xbofs will be changed after the next - * frame is sent. - * If 'now' is true, the speed and xbofs is changed immediately - */ -void irlap_apply_connection_parameters(struct irlap_cb *self, int now) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Set the negotiated xbofs value */ - self->next_bofs = self->qos_tx.additional_bofs.value; - if (now) - self->bofs_count = self->next_bofs; - - /* Set the negotiated link speed (may need the new xbofs value) */ - irlap_change_speed(self, self->qos_tx.baud_rate.value, now); - - self->window_size = self->qos_tx.window_size.value; - self->window = self->qos_tx.window_size.value; - -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - /* - * Calculate how many bytes it is possible to transmit before the - * link must be turned around - */ - self->line_capacity = - irlap_max_line_capacity(self->qos_tx.baud_rate.value, - self->qos_tx.max_turn_time.value); - self->bytes_left = self->line_capacity; -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - - - /* - * Initialize timeout values, some of the rules are listed on - * page 92 in IrLAP. - */ - IRDA_ASSERT(self->qos_tx.max_turn_time.value != 0, return;); - IRDA_ASSERT(self->qos_rx.max_turn_time.value != 0, return;); - /* The poll timeout applies only to the primary station. - * It defines the maximum time the primary stay in XMIT mode - * before timeout and turning the link around (sending a RR). - * Or, this is how much we can keep the pf bit in primary mode. - * Therefore, it must be lower or equal than our *OWN* max turn around. - * Jean II */ - self->poll_timeout = msecs_to_jiffies( - self->qos_tx.max_turn_time.value); - /* The Final timeout applies only to the primary station. - * It defines the maximum time the primary wait (mostly in RECV mode) - * for an answer from the secondary station before polling it again. - * Therefore, it must be greater or equal than our *PARTNER* - * max turn around time - Jean II */ - self->final_timeout = msecs_to_jiffies( - self->qos_rx.max_turn_time.value); - /* The Watchdog Bit timeout applies only to the secondary station. - * It defines the maximum time the secondary wait (mostly in RECV mode) - * for poll from the primary station before getting annoyed. - * Therefore, it must be greater or equal than our *PARTNER* - * max turn around time - Jean II */ - self->wd_timeout = self->final_timeout * 2; - - /* - * N1 and N2 are maximum retry count for *both* the final timer - * and the wd timer (with a factor 2) as defined above. - * After N1 retry of a timer, we give a warning to the user. - * After N2 retry, we consider the link dead and disconnect it. - * Jean II - */ - - /* - * Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to - * 3 seconds otherwise. See page 71 in IrLAP for more details. - * Actually, it's not always 3 seconds, as we allow to set - * it via sysctl... Max maxtt is 500ms, and N1 need to be multiple - * of 2, so 1 second is minimum we can allow. - Jean II - */ - if (self->qos_tx.link_disc_time.value == sysctl_warn_noreply_time) - /* - * If we set N1 to 0, it will trigger immediately, which is - * not what we want. What we really want is to disable it, - * Jean II - */ - self->N1 = -2; /* Disable - Need to be multiple of 2*/ - else - self->N1 = sysctl_warn_noreply_time * 1000 / - self->qos_rx.max_turn_time.value; - - pr_debug("Setting N1 = %d\n", self->N1); - - /* Set N2 to match our own disconnect time */ - self->N2 = self->qos_tx.link_disc_time.value * 1000 / - self->qos_rx.max_turn_time.value; - pr_debug("Setting N2 = %d\n", self->N2); -} - -#ifdef CONFIG_PROC_FS -struct irlap_iter_state { - int id; -}; - -static void *irlap_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct irlap_iter_state *iter = seq->private; - struct irlap_cb *self; - - /* Protect our access to the tsap list */ - spin_lock_irq(&irlap->hb_spinlock); - iter->id = 0; - - for (self = (struct irlap_cb *) hashbin_get_first(irlap); - self; self = (struct irlap_cb *) hashbin_get_next(irlap)) { - if (iter->id == *pos) - break; - ++iter->id; - } - - return self; -} - -static void *irlap_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct irlap_iter_state *iter = seq->private; - - ++*pos; - ++iter->id; - return (void *) hashbin_get_next(irlap); -} - -static void irlap_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_irq(&irlap->hb_spinlock); -} - -static int irlap_seq_show(struct seq_file *seq, void *v) -{ - const struct irlap_iter_state *iter = seq->private; - const struct irlap_cb *self = v; - - IRDA_ASSERT(self->magic == LAP_MAGIC, return -EINVAL;); - - seq_printf(seq, "irlap%d ", iter->id); - seq_printf(seq, "state: %s\n", - irlap_state[self->state]); - - seq_printf(seq, " device name: %s, ", - (self->netdev) ? self->netdev->name : "bug"); - seq_printf(seq, "hardware name: %s\n", self->hw_name); - - seq_printf(seq, " caddr: %#02x, ", self->caddr); - seq_printf(seq, "saddr: %#08x, ", self->saddr); - seq_printf(seq, "daddr: %#08x\n", self->daddr); - - seq_printf(seq, " win size: %d, ", - self->window_size); - seq_printf(seq, "win: %d, ", self->window); -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - seq_printf(seq, "line capacity: %d, ", - self->line_capacity); - seq_printf(seq, "bytes left: %d\n", self->bytes_left); -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - seq_printf(seq, " tx queue len: %d ", - skb_queue_len(&self->txq)); - seq_printf(seq, "win queue len: %d ", - skb_queue_len(&self->wx_list)); - seq_printf(seq, "rbusy: %s", self->remote_busy ? - "TRUE" : "FALSE"); - seq_printf(seq, " mbusy: %s\n", self->media_busy ? - "TRUE" : "FALSE"); - - seq_printf(seq, " retrans: %d ", self->retry_count); - seq_printf(seq, "vs: %d ", self->vs); - seq_printf(seq, "vr: %d ", self->vr); - seq_printf(seq, "va: %d\n", self->va); - - seq_printf(seq, " qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n"); - - seq_printf(seq, " tx\t%d\t", - self->qos_tx.baud_rate.value); - seq_printf(seq, "%d\t", - self->qos_tx.max_turn_time.value); - seq_printf(seq, "%d\t", - self->qos_tx.data_size.value); - seq_printf(seq, "%d\t", - self->qos_tx.window_size.value); - seq_printf(seq, "%d\t", - self->qos_tx.additional_bofs.value); - seq_printf(seq, "%d\t", - self->qos_tx.min_turn_time.value); - seq_printf(seq, "%d\t", - self->qos_tx.link_disc_time.value); - seq_printf(seq, "\n"); - - seq_printf(seq, " rx\t%d\t", - self->qos_rx.baud_rate.value); - seq_printf(seq, "%d\t", - self->qos_rx.max_turn_time.value); - seq_printf(seq, "%d\t", - self->qos_rx.data_size.value); - seq_printf(seq, "%d\t", - self->qos_rx.window_size.value); - seq_printf(seq, "%d\t", - self->qos_rx.additional_bofs.value); - seq_printf(seq, "%d\t", - self->qos_rx.min_turn_time.value); - seq_printf(seq, "%d\n", - self->qos_rx.link_disc_time.value); - - return 0; -} - -static const struct seq_operations irlap_seq_ops = { - .start = irlap_seq_start, - .next = irlap_seq_next, - .stop = irlap_seq_stop, - .show = irlap_seq_show, -}; - -static int irlap_seq_open(struct inode *inode, struct file *file) -{ - if (irlap == NULL) - return -EINVAL; - - return seq_open_private(file, &irlap_seq_ops, - sizeof(struct irlap_iter_state)); -} - -const struct file_operations irlap_seq_fops = { - .owner = THIS_MODULE, - .open = irlap_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - -#endif /* CONFIG_PROC_FS */ diff --git a/drivers/staging/irda/net/irlap_event.c b/drivers/staging/irda/net/irlap_event.c deleted file mode 100644 index 634188b07e0a..000000000000 --- a/drivers/staging/irda/net/irlap_event.c +++ /dev/null @@ -1,2316 +0,0 @@ -/********************************************************************* - * - * Filename: irlap_event.c - * Version: 0.9 - * Description: IrLAP state machine implementation - * Status: Experimental. - * Author: Dag Brattli <dag@brattli.net> - * Created at: Sat Aug 16 00:59:29 1997 - * Modified at: Sat Dec 25 21:07:57 1999 - * Modified by: Dag Brattli <dag@brattli.net> - * - * Copyright (c) 1998-2000 Dag Brattli <dag@brattli.net>, - * Copyright (c) 1998 Thomas Davis <ratbert@radiks.net> - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/skbuff.h> -#include <linux/slab.h> - -#include <net/irda/irda.h> -#include <net/irda/irlap_event.h> - -#include <net/irda/timer.h> -#include <net/irda/irlap.h> -#include <net/irda/irlap_frame.h> -#include <net/irda/qos.h> -#include <net/irda/parameters.h> -#include <net/irda/irlmp.h> /* irlmp_flow_indication(), ... */ - -#include <net/irda/irda_device.h> - -#ifdef CONFIG_IRDA_FAST_RR -int sysctl_fast_poll_increase = 50; -#endif - -static int irlap_state_ndm (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_query (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reply (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_conn (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_setup (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_nrm_p (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_nrm_s (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, - struct sk_buff *, struct irlap_info *); - -static const char *const irlap_event[] __maybe_unused = { - "DISCOVERY_REQUEST", - "CONNECT_REQUEST", - "CONNECT_RESPONSE", - "DISCONNECT_REQUEST", - "DATA_REQUEST", - "RESET_REQUEST", - "RESET_RESPONSE", - "SEND_I_CMD", - "SEND_UI_FRAME", - "RECV_DISCOVERY_XID_CMD", - "RECV_DISCOVERY_XID_RSP", - "RECV_SNRM_CMD", - "RECV_TEST_CMD", - "RECV_TEST_RSP", - "RECV_UA_RSP", - "RECV_DM_RSP", - "RECV_RD_RSP", - "RECV_I_CMD", - "RECV_I_RSP", - "RECV_UI_FRAME", - "RECV_FRMR_RSP", - "RECV_RR_CMD", - "RECV_RR_RSP", - "RECV_RNR_CMD", - "RECV_RNR_RSP", - "RECV_REJ_CMD", - "RECV_REJ_RSP", - "RECV_SREJ_CMD", - "RECV_SREJ_RSP", - "RECV_DISC_CMD", - "SLOT_TIMER_EXPIRED", - "QUERY_TIMER_EXPIRED", - "FINAL_TIMER_EXPIRED", - "POLL_TIMER_EXPIRED", - "DISCOVERY_TIMER_EXPIRED", - "WD_TIMER_EXPIRED", - "BACKOFF_TIMER_EXPIRED", - "MEDIA_BUSY_TIMER_EXPIRED", -}; - -const char *const irlap_state[] = { - "LAP_NDM", - "LAP_QUERY", - "LAP_REPLY", - "LAP_CONN", - "LAP_SETUP", - "LAP_OFFLINE", - "LAP_XMIT_P", - "LAP_PCLOSE", - "LAP_NRM_P", - "LAP_RESET_WAIT", - "LAP_RESET", - "LAP_NRM_S", - "LAP_XMIT_S", - "LAP_SCLOSE", - "LAP_RESET_CHECK", -}; - -static int (*state[])(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) = -{ - irlap_state_ndm, - irlap_state_query, - irlap_state_reply, - irlap_state_conn, - irlap_state_setup, - irlap_state_offline, - irlap_state_xmit_p, - irlap_state_pclose, - irlap_state_nrm_p, - irlap_state_reset_wait, - irlap_state_reset, - irlap_state_nrm_s, - irlap_state_xmit_s, - irlap_state_sclose, - irlap_state_reset_check, -}; - -/* - * Function irda_poll_timer_expired (data) - * - * Poll timer has expired. Normally we must now send a RR frame to the - * remote device - */ -static void irlap_poll_timer_expired(struct timer_list *t) -{ - struct irlap_cb *self = from_timer(self, t, poll_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); -} - -/* - * Calculate and set time before we will have to send back the pf bit - * to the peer. Use in primary. - * Make sure that state is XMIT_P/XMIT_S when calling this function - * (and that nobody messed up with the state). - Jean II - */ -static void irlap_start_poll_timer(struct irlap_cb *self, int timeout) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - -#ifdef CONFIG_IRDA_FAST_RR - /* - * Send out the RR frames faster if our own transmit queue is empty, or - * if the peer is busy. The effect is a much faster conversation - */ - if (skb_queue_empty(&self->txq) || self->remote_busy) { - if (self->fast_RR == TRUE) { - /* - * Assert that the fast poll timer has not reached the - * normal poll timer yet - */ - if (self->fast_RR_timeout < timeout) { - /* - * FIXME: this should be a more configurable - * function - */ - self->fast_RR_timeout += - (sysctl_fast_poll_increase * HZ/1000); - - /* Use this fast(er) timeout instead */ - timeout = self->fast_RR_timeout; - } - } else { - self->fast_RR = TRUE; - - /* Start with just 0 ms */ - self->fast_RR_timeout = 0; - timeout = 0; - } - } else - self->fast_RR = FALSE; - - pr_debug("%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies); -#endif /* CONFIG_IRDA_FAST_RR */ - - if (timeout == 0) - irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); - else - irda_start_timer(&self->poll_timer, timeout, - irlap_poll_timer_expired); -} - -/* - * Function irlap_do_event (event, skb, info) - * - * Rushes through the state machine without any delay. If state == XMIT - * then send queued data frames. - */ -void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret; - - if (!self || self->magic != LAP_MAGIC) - return; - - pr_debug("%s(), event = %s, state = %s\n", __func__, - irlap_event[event], irlap_state[self->state]); - - ret = (*state[self->state])(self, event, skb, info); - - /* - * Check if there are any pending events that needs to be executed - */ - switch (self->state) { - case LAP_XMIT_P: /* FALLTHROUGH */ - case LAP_XMIT_S: - /* - * We just received the pf bit and are at the beginning - * of a new LAP transmit window. - * Check if there are any queued data frames, and do not - * try to disconnect link if we send any data frames, since - * that will change the state away form XMIT - */ - pr_debug("%s() : queue len = %d\n", __func__, - skb_queue_len(&self->txq)); - - if (!skb_queue_empty(&self->txq)) { - /* Prevent race conditions with irlap_data_request() */ - self->local_busy = TRUE; - - /* Theory of operation. - * We send frames up to when we fill the window or - * reach line capacity. Those frames will queue up - * in the device queue, and the driver will slowly - * send them. - * After each frame that we send, we poll the higher - * layer for more data. It's the right time to do - * that because the link layer need to perform the mtt - * and then send the first frame, so we can afford - * to send a bit of time in kernel space. - * The explicit flow indication allow to minimise - * buffers (== lower latency), to avoid higher layer - * polling via timers (== less context switches) and - * to implement a crude scheduler - Jean II */ - - /* Try to send away all queued data frames */ - while ((skb = skb_dequeue(&self->txq)) != NULL) { - /* Send one frame */ - ret = (*state[self->state])(self, SEND_I_CMD, - skb, NULL); - /* Drop reference count. - * It will be increase as needed in - * irlap_send_data_xxx() */ - kfree_skb(skb); - - /* Poll the higher layers for one more frame */ - irlmp_flow_indication(self->notify.instance, - FLOW_START); - - if (ret == -EPROTO) - break; /* Try again later! */ - } - /* Finished transmitting */ - self->local_busy = FALSE; - } else if (self->disconnect_pending) { - self->disconnect_pending = FALSE; - - ret = (*state[self->state])(self, DISCONNECT_REQUEST, - NULL, NULL); - } - break; -/* case LAP_NDM: */ -/* case LAP_CONN: */ -/* case LAP_RESET_WAIT: */ -/* case LAP_RESET_CHECK: */ - default: - break; - } -} - -/* - * Function irlap_state_ndm (event, skb, frame) - * - * NDM (Normal Disconnected Mode) state - * - */ -static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - discovery_t *discovery_rsp; - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case CONNECT_REQUEST: - IRDA_ASSERT(self->netdev != NULL, return -1;); - - if (self->media_busy) { - /* Note : this will never happen, because we test - * media busy in irlap_connect_request() and - * postpone the event... - Jean II */ - pr_debug("%s(), CONNECT_REQUEST: media busy!\n", - __func__); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_MEDIA_BUSY); - } else { - irlap_send_snrm_frame(self, &self->qos_rx); - - /* Start Final-bit timer */ - irlap_start_final_timer(self, self->final_timeout); - - self->retry_count = 0; - irlap_next_state(self, LAP_SETUP); - } - break; - case RECV_SNRM_CMD: - /* Check if the frame contains and I field */ - if (info) { - self->daddr = info->daddr; - self->caddr = info->caddr; - - irlap_next_state(self, LAP_CONN); - - irlap_connect_indication(self, skb); - } else { - pr_debug("%s(), SNRM frame does not contain an I field!\n", - __func__); - } - break; - case DISCOVERY_REQUEST: - IRDA_ASSERT(info != NULL, return -1;); - - if (self->media_busy) { - pr_debug("%s(), DISCOVERY_REQUEST: media busy!\n", - __func__); - /* irlap->log.condition = MEDIA_BUSY; */ - - /* This will make IrLMP try again */ - irlap_discovery_confirm(self, NULL); - /* Note : the discovery log is not cleaned up here, - * it will be done in irlap_discovery_request() - * Jean II */ - return 0; - } - - self->S = info->S; - self->s = info->s; - irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE, - info->discovery); - self->frame_sent = FALSE; - self->s++; - - irlap_start_slot_timer(self, self->slot_timeout); - irlap_next_state(self, LAP_QUERY); - break; - case RECV_DISCOVERY_XID_CMD: - IRDA_ASSERT(info != NULL, return -1;); - - /* Assert that this is not the final slot */ - if (info->s <= info->S) { - self->slot = irlap_generate_rand_time_slot(info->S, - info->s); - if (self->slot == info->s) { - discovery_rsp = irlmp_get_discovery_response(); - discovery_rsp->data.daddr = info->daddr; - - irlap_send_discovery_xid_frame(self, info->S, - self->slot, - FALSE, - discovery_rsp); - self->frame_sent = TRUE; - } else - self->frame_sent = FALSE; - - /* - * Go to reply state until end of discovery to - * inhibit our own transmissions. Set the timer - * to not stay forever there... Jean II - */ - irlap_start_query_timer(self, info->S, info->s); - irlap_next_state(self, LAP_REPLY); - } else { - /* This is the final slot. How is it possible ? - * This would happen is both discoveries are just slightly - * offset (if they are in sync, all packets are lost). - * Most often, all the discovery requests will be received - * in QUERY state (see my comment there), except for the - * last frame that will come here. - * The big trouble when it happen is that active discovery - * doesn't happen, because nobody answer the discoveries - * frame of the other guy, so the log shows up empty. - * What should we do ? - * Not much. It's too late to answer those discovery frames, - * so we just pass the info to IrLMP who will put it in the - * log (and post an event). - * Another cause would be devices that do discovery much - * slower than us, however the latest fixes should minimise - * those cases... - * Jean II - */ - pr_debug("%s(), Receiving final discovery request, missed the discovery slots :-(\n", - __func__); - - /* Last discovery request -> in the log */ - irlap_discovery_indication(self, info->discovery); - } - break; - case MEDIA_BUSY_TIMER_EXPIRED: - /* A bunch of events may be postponed because the media is - * busy (usually immediately after we close a connection), - * or while we are doing discovery (state query/reply). - * In all those cases, the media busy flag will be cleared - * when it's OK for us to process those postponed events. - * This event is not mentioned in the state machines in the - * IrLAP spec. It's because they didn't consider Ultra and - * postponing connection request is optional. - * Jean II */ -#ifdef CONFIG_IRDA_ULTRA - /* Send any pending Ultra frames if any */ - if (!skb_queue_empty(&self->txq_ultra)) { - /* We don't send the frame, just post an event. - * Also, previously this code was in timer.c... - * Jean II */ - ret = (*state[self->state])(self, SEND_UI_FRAME, - NULL, NULL); - } -#endif /* CONFIG_IRDA_ULTRA */ - /* Check if we should try to connect. - * This code was previously in irlap_do_event() */ - if (self->connect_pending) { - self->connect_pending = FALSE; - - /* This one *should* not pend in this state, except - * if a socket try to connect and immediately - * disconnect. - clear - Jean II */ - if (self->disconnect_pending) - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - else - ret = (*state[self->state])(self, - CONNECT_REQUEST, - NULL, NULL); - self->disconnect_pending = FALSE; - } - /* Note : one way to test if this code works well (including - * media busy and small busy) is to create a user space - * application generating an Ultra packet every 3.05 sec (or - * 2.95 sec) and to see how it interact with discovery. - * It's fairly easy to check that no packet is lost, that the - * packets are postponed during discovery and that after - * discovery indication you have a 100ms "gap". - * As connection request and Ultra are now processed the same - * way, this avoid the tedious job of trying IrLAP connection - * in all those cases... - * Jean II */ - break; -#ifdef CONFIG_IRDA_ULTRA - case SEND_UI_FRAME: - { - int i; - /* Only allowed to repeat an operation twice */ - for (i=0; ((i<2) && (self->media_busy == FALSE)); i++) { - skb = skb_dequeue(&self->txq_ultra); - if (skb) - irlap_send_ui_frame(self, skb, CBROADCAST, - CMD_FRAME); - else - break; - /* irlap_send_ui_frame() won't increase skb reference - * count, so no dev_kfree_skb() - Jean II */ - } - if (i == 2) { - /* Force us to listen 500 ms again */ - irda_device_set_media_busy(self->netdev, TRUE); - } - break; - } - case RECV_UI_FRAME: - /* Only accept broadcast frames in NDM mode */ - if (info->caddr != CBROADCAST) { - pr_debug("%s(), not a broadcast frame!\n", - __func__); - } else - irlap_unitdata_indication(self, skb); - break; -#endif /* CONFIG_IRDA_ULTRA */ - case RECV_TEST_CMD: - /* Remove test frame header */ - skb_pull(skb, sizeof(struct test_frame)); - - /* - * Send response. This skb will not be sent out again, and - * will only be used to send out the same info as the cmd - */ - irlap_send_test_frame(self, CBROADCAST, info->daddr, skb); - break; - case RECV_TEST_RSP: - pr_debug("%s() not implemented!\n", __func__); - break; - default: - pr_debug("%s(), Unknown event %s\n", __func__, - irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_query (event, skb, info) - * - * QUERY state - * - */ -static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case RECV_DISCOVERY_XID_RSP: - IRDA_ASSERT(info != NULL, return -1;); - IRDA_ASSERT(info->discovery != NULL, return -1;); - - pr_debug("%s(), daddr=%08x\n", __func__, - info->discovery->data.daddr); - - if (!self->discovery_log) { - net_warn_ratelimited("%s: discovery log is gone! maybe the discovery timeout has been set too short?\n", - __func__); - break; - } - hashbin_insert(self->discovery_log, - (irda_queue_t *) info->discovery, - info->discovery->data.daddr, NULL); - - /* Keep state */ - /* irlap_next_state(self, LAP_QUERY); */ - - break; - case RECV_DISCOVERY_XID_CMD: - /* Yes, it is possible to receive those frames in this mode. - * Note that most often the last discovery request won't - * occur here but in NDM state (see my comment there). - * What should we do ? - * Not much. We are currently performing our own discovery, - * therefore we can't answer those frames. We don't want - * to change state either. We just pass the info to - * IrLMP who will put it in the log (and post an event). - * Jean II - */ - - IRDA_ASSERT(info != NULL, return -1;); - - pr_debug("%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", - __func__, info->s); - - /* Last discovery request ? */ - if (info->s == 0xff) - irlap_discovery_indication(self, info->discovery); - break; - case SLOT_TIMER_EXPIRED: - /* - * Wait a little longer if we detect an incoming frame. This - * is not mentioned in the spec, but is a good thing to do, - * since we want to work even with devices that violate the - * timing requirements. - */ - if (irda_device_is_receiving(self->netdev) && !self->add_wait) { - pr_debug("%s(), device is slow to answer, waiting some more!\n", - __func__); - irlap_start_slot_timer(self, msecs_to_jiffies(10)); - self->add_wait = TRUE; - return ret; - } - self->add_wait = FALSE; - - if (self->s < self->S) { - irlap_send_discovery_xid_frame(self, self->S, - self->s, TRUE, - self->discovery_cmd); - self->s++; - irlap_start_slot_timer(self, self->slot_timeout); - - /* Keep state */ - irlap_next_state(self, LAP_QUERY); - } else { - /* This is the final slot! */ - irlap_send_discovery_xid_frame(self, self->S, 0xff, - TRUE, - self->discovery_cmd); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - /* - * We are now finished with the discovery procedure, - * so now we must return the results - */ - irlap_discovery_confirm(self, self->discovery_log); - - /* IrLMP should now have taken care of the log */ - self->discovery_log = NULL; - } - break; - default: - pr_debug("%s(), Unknown event %s\n", __func__, - irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_reply (self, event, skb, info) - * - * REPLY, we have received a XID discovery frame from a device and we - * are waiting for the right time slot to send a response XID frame - * - */ -static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - discovery_t *discovery_rsp; - int ret=0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case QUERY_TIMER_EXPIRED: - pr_debug("%s(), QUERY_TIMER_EXPIRED <%ld>\n", - __func__, jiffies); - irlap_next_state(self, LAP_NDM); - break; - case RECV_DISCOVERY_XID_CMD: - IRDA_ASSERT(info != NULL, return -1;); - /* Last frame? */ - if (info->s == 0xff) { - del_timer(&self->query_timer); - - /* info->log.condition = REMOTE; */ - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_discovery_indication(self, info->discovery); - } else { - /* If it's our slot, send our reply */ - if ((info->s >= self->slot) && (!self->frame_sent)) { - discovery_rsp = irlmp_get_discovery_response(); - discovery_rsp->data.daddr = info->daddr; - - irlap_send_discovery_xid_frame(self, info->S, - self->slot, - FALSE, - discovery_rsp); - - self->frame_sent = TRUE; - } - /* Readjust our timer to accommodate devices - * doing faster or slower discovery than us... - * Jean II */ - irlap_start_query_timer(self, info->S, info->s); - - /* Keep state */ - //irlap_next_state(self, LAP_REPLY); - } - break; - default: - pr_debug("%s(), Unknown event %d, %s\n", __func__, - event, irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_conn (event, skb, info) - * - * CONN, we have received a SNRM command and is waiting for the upper - * layer to accept or refuse connection - * - */ -static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case CONNECT_RESPONSE: - skb_pull(skb, sizeof(struct snrm_frame)); - - IRDA_ASSERT(self->netdev != NULL, return -1;); - - irlap_qos_negotiate(self, skb); - - irlap_initiate_connection_state(self); - - /* - * Applying the parameters now will make sure we change speed - * *after* we have sent the next frame - */ - irlap_apply_connection_parameters(self, FALSE); - - /* - * Sending this frame will force a speed change after it has - * been sent (i.e. the frame will be sent at 9600). - */ - irlap_send_ua_response_frame(self, &self->qos_rx); - -#if 0 - /* - * We are allowed to send two frames, but this may increase - * the connect latency, so lets not do it for now. - */ - /* This is full of good intentions, but doesn't work in - * practice. - * After sending the first UA response, we switch the - * dongle to the negotiated speed, which is usually - * different than 9600 kb/s. - * From there, there is two solutions : - * 1) The other end has received the first UA response : - * it will set up the connection, move to state LAP_NRM_P, - * and will ignore and drop the second UA response. - * Actually, it's even worse : the other side will almost - * immediately send a RR that will likely collide with the - * UA response (depending on negotiated turnaround). - * 2) The other end has not received the first UA response, - * will stay at 9600 and will never see the second UA response. - * Jean II */ - irlap_send_ua_response_frame(self, &self->qos_rx); -#endif - - /* - * The WD-timer could be set to the duration of the P-timer - * for this case, but it is recommended to use twice the - * value (note 3 IrLAP p. 60). - */ - irlap_start_wd_timer(self, self->wd_timeout); - irlap_next_state(self, LAP_NRM_S); - - break; - case RECV_DISCOVERY_XID_CMD: - pr_debug("%s(), event RECV_DISCOVER_XID_CMD!\n", - __func__); - irlap_next_state(self, LAP_NDM); - - break; - case DISCONNECT_REQUEST: - pr_debug("%s(), Disconnect request!\n", __func__); - irlap_send_dm_frame(self); - irlap_next_state( self, LAP_NDM); - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - default: - pr_debug("%s(), Unknown event %d, %s\n", __func__, - event, irlap_event[event]); - - ret = -1; - break; - } - - return ret; -} - -/* - * Function irlap_state_setup (event, skb, frame) - * - * SETUP state, The local layer has transmitted a SNRM command frame to - * a remote peer layer and is awaiting a reply . - * - */ -static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case FINAL_TIMER_EXPIRED: - if (self->retry_count < self->N3) { -/* - * Perform random backoff, Wait a random number of time units, minimum - * duration half the time taken to transmitt a SNRM frame, maximum duration - * 1.5 times the time taken to transmit a SNRM frame. So this time should - * between 15 msecs and 45 msecs. - */ - irlap_start_backoff_timer(self, msecs_to_jiffies(20 + - (jiffies % 30))); - } else { - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_FOUND_NONE); - } - break; - case BACKOFF_TIMER_EXPIRED: - irlap_send_snrm_frame(self, &self->qos_rx); - irlap_start_final_timer(self, self->final_timeout); - self->retry_count++; - break; - case RECV_SNRM_CMD: - pr_debug("%s(), SNRM battle!\n", __func__); - - IRDA_ASSERT(skb != NULL, return 0;); - IRDA_ASSERT(info != NULL, return 0;); - - /* - * The device with the largest device address wins the battle - * (both have sent a SNRM command!) - */ - if (info &&(info->daddr > self->saddr)) { - del_timer(&self->final_timer); - irlap_initiate_connection_state(self); - - IRDA_ASSERT(self->netdev != NULL, return -1;); - - skb_pull(skb, sizeof(struct snrm_frame)); - - irlap_qos_negotiate(self, skb); - - /* Send UA frame and then change link settings */ - irlap_apply_connection_parameters(self, FALSE); - irlap_send_ua_response_frame(self, &self->qos_rx); - - irlap_next_state(self, LAP_NRM_S); - irlap_connect_confirm(self, skb); - - /* - * The WD-timer could be set to the duration of the - * P-timer for this case, but it is recommended - * to use twice the value (note 3 IrLAP p. 60). - */ - irlap_start_wd_timer(self, self->wd_timeout); - } else { - /* We just ignore the other device! */ - irlap_next_state(self, LAP_SETUP); - } - break; - case RECV_UA_RSP: - /* Stop F-timer */ - del_timer(&self->final_timer); - - /* Initiate connection state */ - irlap_initiate_connection_state(self); - - /* Negotiate connection parameters */ - IRDA_ASSERT(skb->len > 10, return -1;); - - skb_pull(skb, sizeof(struct ua_frame)); - - IRDA_ASSERT(self->netdev != NULL, return -1;); - - irlap_qos_negotiate(self, skb); - - /* Set the new link setting *now* (before the rr frame) */ - irlap_apply_connection_parameters(self, TRUE); - self->retry_count = 0; - - /* Wait for turnaround time to give a chance to the other - * device to be ready to receive us. - * Note : the time to switch speed is typically larger - * than the turnaround time, but as we don't have the other - * side speed switch time, that's our best guess... - * Jean II */ - irlap_wait_min_turn_around(self, &self->qos_tx); - - /* This frame will actually be sent at the new speed */ - irlap_send_rr_frame(self, CMD_FRAME); - - /* The timer is set to half the normal timer to quickly - * detect a failure to negotiate the new connection - * parameters. IrLAP 6.11.3.2, note 3. - * Note that currently we don't process this failure - * properly, as we should do a quick disconnect. - * Jean II */ - irlap_start_final_timer(self, self->final_timeout/2); - irlap_next_state(self, LAP_NRM_P); - - irlap_connect_confirm(self, skb); - break; - case RECV_DM_RSP: /* FALLTHROUGH */ - case RECV_DISC_CMD: - del_timer(&self->final_timer); - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - default: - pr_debug("%s(), Unknown event %d, %s\n", __func__, - event, irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_offline (self, event, skb, info) - * - * OFFLINE state, not used for now! - * - */ -static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - pr_debug("%s(), Unknown event\n", __func__); - - return -1; -} - -/* - * Function irlap_state_xmit_p (self, event, skb, info) - * - * XMIT, Only the primary station has right to transmit, and we - * therefore do not expect to receive any transmissions from other - * stations. - * - */ -static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - switch (event) { - case SEND_I_CMD: - /* - * Only send frame if send-window > 0. - */ - if ((self->window > 0) && (!self->remote_busy)) { - int nextfit; -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - struct sk_buff *skb_next; - - /* With DYNAMIC_WINDOW, we keep the window size - * maximum, and adapt on the packets we are sending. - * At 115k, we can send only 2 packets of 2048 bytes - * in a 500 ms turnaround. Without this option, we - * would always limit the window to 2. With this - * option, if we send smaller packets, we can send - * up to 7 of them (always depending on QoS). - * Jean II */ - - /* Look at the next skb. This is safe, as we are - * the only consumer of the Tx queue (if we are not, - * we have other problems) - Jean II */ - skb_next = skb_peek(&self->txq); - - /* Check if a subsequent skb exist and would fit in - * the current window (with respect to turnaround - * time). - * This allow us to properly mark the current packet - * with the pf bit, to avoid falling back on the - * second test below, and avoid waiting the - * end of the window and sending a extra RR. - * Note : (skb_next != NULL) <=> (skb_queue_len() > 0) - * Jean II */ - nextfit = ((skb_next != NULL) && - ((skb_next->len + skb->len) <= - self->bytes_left)); - - /* - * The current packet may not fit ! Because of test - * above, this should not happen any more !!! - * Test if we have transmitted more bytes over the - * link than its possible to do with the current - * speed and turn-around-time. - */ - if((!nextfit) && (skb->len > self->bytes_left)) { - pr_debug("%s(), Not allowed to transmit more bytes!\n", - __func__); - /* Requeue the skb */ - skb_queue_head(&self->txq, skb_get(skb)); - /* - * We should switch state to LAP_NRM_P, but - * that is not possible since we must be sure - * that we poll the other side. Since we have - * used up our time, the poll timer should - * trigger anyway now, so we just wait for it - * DB - */ - /* - * Sorry, but that's not totally true. If - * we send 2000B packets, we may wait another - * 1000B until our turnaround expire. That's - * why we need to be proactive in avoiding - * coming here. - Jean II - */ - return -EPROTO; - } - - /* Subtract space used by this skb */ - self->bytes_left -= skb->len; -#else /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* Window has been adjusted for the max packet - * size, so much simpler... - Jean II */ - nextfit = !skb_queue_empty(&self->txq); -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* - * Send data with poll bit cleared only if window > 1 - * and there is more frames after this one to be sent - */ - if ((self->window > 1) && (nextfit)) { - /* More packet to send in current window */ - irlap_send_data_primary(self, skb); - irlap_next_state(self, LAP_XMIT_P); - } else { - /* Final packet of window */ - irlap_send_data_primary_poll(self, skb); - - /* - * Make sure state machine does not try to send - * any more frames - */ - ret = -EPROTO; - } -#ifdef CONFIG_IRDA_FAST_RR - /* Peer may want to reply immediately */ - self->fast_RR = FALSE; -#endif /* CONFIG_IRDA_FAST_RR */ - } else { - pr_debug("%s(), Unable to send! remote busy?\n", - __func__); - skb_queue_head(&self->txq, skb_get(skb)); - - /* - * The next ret is important, because it tells - * irlap_next_state _not_ to deliver more frames - */ - ret = -EPROTO; - } - break; - case POLL_TIMER_EXPIRED: - pr_debug("%s(), POLL_TIMER_EXPIRED <%ld>\n", - __func__, jiffies); - irlap_send_rr_frame(self, CMD_FRAME); - /* Return to NRM properly - Jean II */ - self->window = self->window_size; -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - /* Allowed to transmit a maximum number of bytes again. */ - self->bytes_left = self->line_capacity; -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_NRM_P); - break; - case DISCONNECT_REQUEST: - del_timer(&self->poll_timer); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_disc_frame(self); - irlap_flush_all_queues(self); - irlap_start_final_timer(self, self->final_timeout); - self->retry_count = 0; - irlap_next_state(self, LAP_PCLOSE); - break; - case DATA_REQUEST: - /* Nothing to do, irlap_do_event() will send the packet - * when we return... - Jean II */ - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlap_event[event]); - - ret = -EINVAL; - break; - } - return ret; -} - -/* - * Function irlap_state_pclose (event, skb, info) - * - * PCLOSE state - */ -static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case RECV_UA_RSP: /* FALLTHROUGH */ - case RECV_DM_RSP: - del_timer(&self->final_timer); - - /* Set new link parameters */ - irlap_apply_default_connection_parameters(self); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - case FINAL_TIMER_EXPIRED: - if (self->retry_count < self->N3) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_disc_frame(self); - irlap_start_final_timer(self, self->final_timeout); - self->retry_count++; - /* Keep state */ - } else { - irlap_apply_default_connection_parameters(self); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_NO_RESPONSE); - } - break; - default: - pr_debug("%s(), Unknown event %d\n", __func__, event); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_nrm_p (self, event, skb, info) - * - * NRM_P (Normal Response Mode as Primary), The primary station has given - * permissions to a secondary station to transmit IrLAP resonse frames - * (by sending a frame with the P bit set). The primary station will not - * transmit any frames and is expecting to receive frames only from the - * secondary to which transmission permissions has been given. - */ -static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - int ns_status; - int nr_status; - - switch (event) { - case RECV_I_RSP: /* Optimize for the common case */ - if (unlikely(skb->len <= LAP_ADDR_HEADER + LAP_CTRL_HEADER)) { - /* - * Input validation check: a stir4200/mcp2150 - * combination sometimes results in an empty i:rsp. - * This makes no sense; we can just ignore the frame - * and send an rr:cmd immediately. This happens before - * changing nr or ns so triggers a retransmit - */ - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - /* Keep state */ - break; - } - /* FIXME: must check for remote_busy below */ -#ifdef CONFIG_IRDA_FAST_RR - /* - * Reset the fast_RR so we can use the fast RR code with - * full speed the next time since peer may have more frames - * to transmitt - */ - self->fast_RR = FALSE; -#endif /* CONFIG_IRDA_FAST_RR */ - IRDA_ASSERT( info != NULL, return -1;); - - ns_status = irlap_validate_ns_received(self, info->ns); - nr_status = irlap_validate_nr_received(self, info->nr); - - /* - * Check for expected I(nformation) frame - */ - if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) { - - /* Update Vr (next frame for us to receive) */ - self->vr = (self->vr + 1) % 8; - - /* Update Nr received, cleanup our retry queue */ - irlap_update_nr_received(self, info->nr); - - /* - * Got expected NR, so reset the - * retry_count. This is not done by IrLAP spec, - * which is strange! - */ - self->retry_count = 0; - self->ack_required = TRUE; - - /* poll bit cleared? */ - if (!info->pf) { - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_P); - - irlap_data_indication(self, skb, FALSE); - } else { - /* No longer waiting for pf */ - del_timer(&self->final_timer); - - irlap_wait_min_turn_around(self, &self->qos_tx); - - /* Call higher layer *before* changing state - * to give them a chance to send data in the - * next LAP frame. - * Jean II */ - irlap_data_indication(self, skb, FALSE); - - /* XMIT states are the most dangerous state - * to be in, because user requests are - * processed directly and may change state. - * On the other hand, in NDM_P, those - * requests are queued and we will process - * them when we return to irlap_do_event(). - * Jean II - */ - irlap_next_state(self, LAP_XMIT_P); - - /* This is the last frame. - * Make sure it's always called in XMIT state. - * - Jean II */ - irlap_start_poll_timer(self, self->poll_timeout); - } - break; - - } - /* Unexpected next to send (Ns) */ - if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED)) - { - if (!info->pf) { - irlap_update_nr_received(self, info->nr); - - /* - * Wait until the last frame before doing - * anything - */ - - /* Keep state */ - irlap_next_state(self, LAP_NRM_P); - } else { - pr_debug("%s(), missing or duplicate frame!\n", - __func__); - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - - self->ack_required = FALSE; - - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_NRM_P); - } - break; - } - /* - * Unexpected next to receive (Nr) - */ - if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED)) - { - if (info->pf) { - self->vr = (self->vr + 1) % 8; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - /* Resend rejected frames */ - irlap_resend_rejected_frames(self, CMD_FRAME); - - self->ack_required = FALSE; - - /* Make sure we account for the time - * to transmit our frames. See comemnts - * in irlap_send_data_primary_poll(). - * Jean II */ - irlap_start_final_timer(self, 2 * self->final_timeout); - - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_P); - - irlap_data_indication(self, skb, FALSE); - } else { - /* - * Do not resend frames until the last - * frame has arrived from the other - * device. This is not documented in - * IrLAP!! - */ - self->vr = (self->vr + 1) % 8; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - self->ack_required = FALSE; - - /* Keep state, do not move this line!*/ - irlap_next_state(self, LAP_NRM_P); - - irlap_data_indication(self, skb, FALSE); - } - break; - } - /* - * Unexpected next to send (Ns) and next to receive (Nr) - * Not documented by IrLAP! - */ - if ((ns_status == NS_UNEXPECTED) && - (nr_status == NR_UNEXPECTED)) - { - pr_debug("%s(), unexpected nr and ns!\n", - __func__); - if (info->pf) { - /* Resend rejected frames */ - irlap_resend_rejected_frames(self, CMD_FRAME); - - /* Give peer some time to retransmit! - * But account for our own Tx. */ - irlap_start_final_timer(self, 2 * self->final_timeout); - - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_P); - } else { - /* Update Nr received */ - /* irlap_update_nr_received( info->nr); */ - - self->ack_required = FALSE; - } - break; - } - - /* - * Invalid NR or NS - */ - if ((nr_status == NR_INVALID) || (ns_status == NS_INVALID)) { - if (info->pf) { - del_timer(&self->final_timer); - - irlap_next_state(self, LAP_RESET_WAIT); - - irlap_disconnect_indication(self, LAP_RESET_INDICATION); - self->xmitflag = TRUE; - } else { - del_timer(&self->final_timer); - - irlap_disconnect_indication(self, LAP_RESET_INDICATION); - - self->xmitflag = FALSE; - } - break; - } - pr_debug("%s(), Not implemented!\n", __func__); - pr_debug("%s(), event=%s, ns_status=%d, nr_status=%d\n", - __func__, irlap_event[event], ns_status, nr_status); - break; - case RECV_UI_FRAME: - /* Poll bit cleared? */ - if (!info->pf) { - irlap_data_indication(self, skb, TRUE); - irlap_next_state(self, LAP_NRM_P); - } else { - del_timer(&self->final_timer); - irlap_data_indication(self, skb, TRUE); - irlap_next_state(self, LAP_XMIT_P); - pr_debug("%s: RECV_UI_FRAME: next state %s\n", - __func__, irlap_state[self->state]); - irlap_start_poll_timer(self, self->poll_timeout); - } - break; - case RECV_RR_RSP: - /* - * If you get a RR, the remote isn't busy anymore, - * no matter what the NR - */ - self->remote_busy = FALSE; - - /* Stop final timer */ - del_timer(&self->final_timer); - - /* - * Nr as expected? - */ - ret = irlap_validate_nr_received(self, info->nr); - if (ret == NR_EXPECTED) { - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - /* - * Got expected NR, so reset the retry_count. This - * is not done by the IrLAP standard , which is - * strange! DB. - */ - self->retry_count = 0; - irlap_wait_min_turn_around(self, &self->qos_tx); - - irlap_next_state(self, LAP_XMIT_P); - - /* Start poll timer */ - irlap_start_poll_timer(self, self->poll_timeout); - } else if (ret == NR_UNEXPECTED) { - IRDA_ASSERT(info != NULL, return -1;); - /* - * Unexpected nr! - */ - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - pr_debug("RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n", - self->retry_count, info->nr, self->va, - self->vs, self->vr); - - /* Resend rejected frames */ - irlap_resend_rejected_frames(self, CMD_FRAME); - irlap_start_final_timer(self, self->final_timeout * 2); - - irlap_next_state(self, LAP_NRM_P); - } else if (ret == NR_INVALID) { - pr_debug("%s(), Received RR with invalid nr !\n", - __func__); - - irlap_next_state(self, LAP_RESET_WAIT); - - irlap_disconnect_indication(self, LAP_RESET_INDICATION); - self->xmitflag = TRUE; - } - break; - case RECV_RNR_RSP: - IRDA_ASSERT(info != NULL, return -1;); - - /* Stop final timer */ - del_timer(&self->final_timer); - self->remote_busy = TRUE; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - irlap_next_state(self, LAP_XMIT_P); - - /* Start poll timer */ - irlap_start_poll_timer(self, self->poll_timeout); - break; - case RECV_FRMR_RSP: - del_timer(&self->final_timer); - self->xmitflag = TRUE; - irlap_next_state(self, LAP_RESET_WAIT); - irlap_reset_indication(self); - break; - case FINAL_TIMER_EXPIRED: - /* - * We are allowed to wait for additional 300 ms if - * final timer expires when we are in the middle - * of receiving a frame (page 45, IrLAP). Check that - * we only do this once for each frame. - */ - if (irda_device_is_receiving(self->netdev) && !self->add_wait) { - pr_debug("FINAL_TIMER_EXPIRED when receiving a frame! Waiting a little bit more!\n"); - irlap_start_final_timer(self, msecs_to_jiffies(300)); - - /* - * Don't allow this to happen one more time in a row, - * or else we can get a pretty tight loop here if - * if we only receive half a frame. DB. - */ - self->add_wait = TRUE; - break; - } - self->add_wait = FALSE; - - /* N2 is the disconnect timer. Until we reach it, we retry */ - if (self->retry_count < self->N2) { - if (skb_peek(&self->wx_list) == NULL) { - /* Retry sending the pf bit to the secondary */ - pr_debug("nrm_p: resending rr"); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - } else { - pr_debug("nrm_p: resend frames"); - irlap_resend_rejected_frames(self, CMD_FRAME); - } - - irlap_start_final_timer(self, self->final_timeout); - self->retry_count++; - pr_debug("irlap_state_nrm_p: FINAL_TIMER_EXPIRED: retry_count=%d\n", - self->retry_count); - - /* Early warning event. I'm using a pretty liberal - * interpretation of the spec and generate an event - * every time the timer is multiple of N1 (and not - * only the first time). This allow application - * to know precisely if connectivity restart... - * Jean II */ - if((self->retry_count % self->N1) == 0) - irlap_status_indication(self, - STATUS_NO_ACTIVITY); - - /* Keep state */ - } else { - irlap_apply_default_connection_parameters(self); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - irlap_disconnect_indication(self, LAP_NO_RESPONSE); - } - break; - case RECV_REJ_RSP: - irlap_update_nr_received(self, info->nr); - if (self->remote_busy) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - } else - irlap_resend_rejected_frames(self, CMD_FRAME); - irlap_start_final_timer(self, 2 * self->final_timeout); - break; - case RECV_SREJ_RSP: - irlap_update_nr_received(self, info->nr); - if (self->remote_busy) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, CMD_FRAME); - } else - irlap_resend_rejected_frame(self, CMD_FRAME); - irlap_start_final_timer(self, 2 * self->final_timeout); - break; - case RECV_RD_RSP: - pr_debug("%s(), RECV_RD_RSP\n", __func__); - - irlap_flush_all_queues(self); - irlap_next_state(self, LAP_XMIT_P); - /* Call back the LAP state machine to do a proper disconnect */ - irlap_disconnect_request(self); - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_reset_wait (event, skb, info) - * - * We have informed the service user of a reset condition, and is - * awaiting reset of disconnect request. - * - */ -static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event = %s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case RESET_REQUEST: - if (self->xmitflag) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_snrm_frame(self, NULL); - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_RESET); - } else { - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_RESET); - } - break; - case DISCONNECT_REQUEST: - irlap_wait_min_turn_around( self, &self->qos_tx); - irlap_send_disc_frame( self); - irlap_flush_all_queues( self); - irlap_start_final_timer( self, self->final_timeout); - self->retry_count = 0; - irlap_next_state( self, LAP_PCLOSE); - break; - default: - pr_debug("%s(), Unknown event %s\n", __func__, - irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_reset (self, event, skb, info) - * - * We have sent a SNRM reset command to the peer layer, and is awaiting - * reply. - * - */ -static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event = %s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case RECV_DISC_CMD: - del_timer(&self->final_timer); - - irlap_apply_default_connection_parameters(self); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_NO_RESPONSE); - - break; - case RECV_UA_RSP: - del_timer(&self->final_timer); - - /* Initiate connection state */ - irlap_initiate_connection_state(self); - - irlap_reset_confirm(); - - self->remote_busy = FALSE; - - irlap_next_state(self, LAP_XMIT_P); - - irlap_start_poll_timer(self, self->poll_timeout); - - break; - case FINAL_TIMER_EXPIRED: - if (self->retry_count < 3) { - irlap_wait_min_turn_around(self, &self->qos_tx); - - IRDA_ASSERT(self->netdev != NULL, return -1;); - irlap_send_snrm_frame(self, self->qos_dev); - - self->retry_count++; /* Experimental!! */ - - irlap_start_final_timer(self, self->final_timeout); - irlap_next_state(self, LAP_RESET); - } else if (self->retry_count >= self->N3) { - irlap_apply_default_connection_parameters(self); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_disconnect_indication(self, LAP_NO_RESPONSE); - } - break; - case RECV_SNRM_CMD: - /* - * SNRM frame is not allowed to contain an I-field in this - * state - */ - if (!info) { - pr_debug("%s(), RECV_SNRM_CMD\n", __func__); - irlap_initiate_connection_state(self); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_ua_response_frame(self, &self->qos_rx); - irlap_reset_confirm(); - irlap_start_wd_timer(self, self->wd_timeout); - irlap_next_state(self, LAP_NDM); - } else { - pr_debug("%s(), SNRM frame contained an I field!\n", - __func__); - } - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlap_event[event]); - - ret = -1; - break; - } - return ret; -} - -/* - * Function irlap_state_xmit_s (event, skb, info) - * - * XMIT_S, The secondary station has been given the right to transmit, - * and we therefore do not expect to receive any transmissions from other - * stations. - */ -static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -ENODEV;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); - - switch (event) { - case SEND_I_CMD: - /* - * Send frame only if send window > 0 - */ - if ((self->window > 0) && (!self->remote_busy)) { - int nextfit; -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - struct sk_buff *skb_next; - - /* - * Same deal as in irlap_state_xmit_p(), so see - * the comments at that point. - * We are the secondary, so there are only subtle - * differences. - Jean II - */ - - /* Check if a subsequent skb exist and would fit in - * the current window (with respect to turnaround - * time). - Jean II */ - skb_next = skb_peek(&self->txq); - nextfit = ((skb_next != NULL) && - ((skb_next->len + skb->len) <= - self->bytes_left)); - - /* - * Test if we have transmitted more bytes over the - * link than its possible to do with the current - * speed and turn-around-time. - */ - if((!nextfit) && (skb->len > self->bytes_left)) { - pr_debug("%s(), Not allowed to transmit more bytes!\n", - __func__); - /* Requeue the skb */ - skb_queue_head(&self->txq, skb_get(skb)); - - /* - * Switch to NRM_S, this is only possible - * when we are in secondary mode, since we - * must be sure that we don't miss any RR - * frames - */ - self->window = self->window_size; - self->bytes_left = self->line_capacity; - irlap_start_wd_timer(self, self->wd_timeout); - - irlap_next_state(self, LAP_NRM_S); - /* Slight difference with primary : - * here we would wait for the other side to - * expire the turnaround. - Jean II */ - - return -EPROTO; /* Try again later */ - } - /* Subtract space used by this skb */ - self->bytes_left -= skb->len; -#else /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* Window has been adjusted for the max packet - * size, so much simpler... - Jean II */ - nextfit = !skb_queue_empty(&self->txq); -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* - * Send data with final bit cleared only if window > 1 - * and there is more frames to be sent - */ - if ((self->window > 1) && (nextfit)) { - irlap_send_data_secondary(self, skb); - irlap_next_state(self, LAP_XMIT_S); - } else { - irlap_send_data_secondary_final(self, skb); - irlap_next_state(self, LAP_NRM_S); - - /* - * Make sure state machine does not try to send - * any more frames - */ - ret = -EPROTO; - } - } else { - pr_debug("%s(), Unable to send!\n", __func__); - skb_queue_head(&self->txq, skb_get(skb)); - ret = -EPROTO; - } - break; - case DISCONNECT_REQUEST: - irlap_send_rd_frame(self); - irlap_flush_all_queues(self); - irlap_start_wd_timer(self, self->wd_timeout); - irlap_next_state(self, LAP_SCLOSE); - break; - case DATA_REQUEST: - /* Nothing to do, irlap_do_event() will send the packet - * when we return... - Jean II */ - break; - default: - pr_debug("%s(), Unknown event %s\n", __func__, - irlap_event[event]); - - ret = -EINVAL; - break; - } - return ret; -} - -/* - * Function irlap_state_nrm_s (event, skb, info) - * - * NRM_S (Normal Response Mode as Secondary) state, in this state we are - * expecting to receive frames from the primary station - * - */ -static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - int ns_status; - int nr_status; - int ret = 0; - - pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - switch (event) { - case RECV_I_CMD: /* Optimize for the common case */ - /* FIXME: must check for remote_busy below */ - pr_debug("%s(), event=%s nr=%d, vs=%d, ns=%d, vr=%d, pf=%d\n", - __func__, irlap_event[event], info->nr, - self->vs, info->ns, self->vr, info->pf); - - self->retry_count = 0; - - ns_status = irlap_validate_ns_received(self, info->ns); - nr_status = irlap_validate_nr_received(self, info->nr); - /* - * Check for expected I(nformation) frame - */ - if ((ns_status == NS_EXPECTED) && (nr_status == NR_EXPECTED)) { - - /* Update Vr (next frame for us to receive) */ - self->vr = (self->vr + 1) % 8; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - /* - * poll bit cleared? - */ - if (!info->pf) { - - self->ack_required = TRUE; - - /* - * Starting WD-timer here is optional, but - * not recommended. Note 6 IrLAP p. 83 - */ -#if 0 - irda_start_timer(WD_TIMER, self->wd_timeout); -#endif - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_S); - - irlap_data_indication(self, skb, FALSE); - break; - } else { - /* - * We should wait before sending RR, and - * also before changing to XMIT_S - * state. (note 1, IrLAP p. 82) - */ - irlap_wait_min_turn_around(self, &self->qos_tx); - - /* - * Give higher layers a chance to - * immediately reply with some data before - * we decide if we should send a RR frame - * or not - */ - irlap_data_indication(self, skb, FALSE); - - /* Any pending data requests? */ - if (!skb_queue_empty(&self->txq) && - (self->window > 0)) - { - self->ack_required = TRUE; - - del_timer(&self->wd_timer); - - irlap_next_state(self, LAP_XMIT_S); - } else { - irlap_send_rr_frame(self, RSP_FRAME); - irlap_start_wd_timer(self, - self->wd_timeout); - - /* Keep the state */ - irlap_next_state(self, LAP_NRM_S); - } - break; - } - } - /* - * Check for Unexpected next to send (Ns) - */ - if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED)) - { - /* Unexpected next to send, with final bit cleared */ - if (!info->pf) { - irlap_update_nr_received(self, info->nr); - - irlap_start_wd_timer(self, self->wd_timeout); - } else { - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, RSP_FRAME); - - irlap_start_wd_timer(self, self->wd_timeout); - } - break; - } - - /* - * Unexpected Next to Receive(NR) ? - */ - if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED)) - { - if (info->pf) { - pr_debug("RECV_I_RSP: frame(s) lost\n"); - - self->vr = (self->vr + 1) % 8; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - /* Resend rejected frames */ - irlap_resend_rejected_frames(self, RSP_FRAME); - - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_S); - - irlap_data_indication(self, skb, FALSE); - irlap_start_wd_timer(self, self->wd_timeout); - break; - } - /* - * This is not documented in IrLAP!! Unexpected NR - * with poll bit cleared - */ - if (!info->pf) { - self->vr = (self->vr + 1) % 8; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - - /* Keep state, do not move this line */ - irlap_next_state(self, LAP_NRM_S); - - irlap_data_indication(self, skb, FALSE); - irlap_start_wd_timer(self, self->wd_timeout); - } - break; - } - - if (ret == NR_INVALID) { - pr_debug("NRM_S, NR_INVALID not implemented!\n"); - } - if (ret == NS_INVALID) { - pr_debug("NRM_S, NS_INVALID not implemented!\n"); - } - break; - case RECV_UI_FRAME: - /* - * poll bit cleared? - */ - if (!info->pf) { - irlap_data_indication(self, skb, TRUE); - irlap_next_state(self, LAP_NRM_S); /* Keep state */ - } else { - /* - * Any pending data requests? - */ - if (!skb_queue_empty(&self->txq) && - (self->window > 0) && !self->remote_busy) - { - irlap_data_indication(self, skb, TRUE); - - del_timer(&self->wd_timer); - - irlap_next_state(self, LAP_XMIT_S); - } else { - irlap_data_indication(self, skb, TRUE); - - irlap_wait_min_turn_around(self, &self->qos_tx); - - irlap_send_rr_frame(self, RSP_FRAME); - self->ack_required = FALSE; - - irlap_start_wd_timer(self, self->wd_timeout); - - /* Keep the state */ - irlap_next_state(self, LAP_NRM_S); - } - } - break; - case RECV_RR_CMD: - self->retry_count = 0; - - /* - * Nr as expected? - */ - nr_status = irlap_validate_nr_received(self, info->nr); - if (nr_status == NR_EXPECTED) { - if (!skb_queue_empty(&self->txq) && - (self->window > 0)) { - self->remote_busy = FALSE; - - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - del_timer(&self->wd_timer); - - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_next_state(self, LAP_XMIT_S); - } else { - self->remote_busy = FALSE; - /* Update Nr received */ - irlap_update_nr_received(self, info->nr); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_start_wd_timer(self, self->wd_timeout); - - /* Note : if the link is idle (this case), - * we never go in XMIT_S, so we never get a - * chance to process any DISCONNECT_REQUEST. - * Do it now ! - Jean II */ - if (self->disconnect_pending) { - /* Disconnect */ - irlap_send_rd_frame(self); - irlap_flush_all_queues(self); - - irlap_next_state(self, LAP_SCLOSE); - } else { - /* Just send back pf bit */ - irlap_send_rr_frame(self, RSP_FRAME); - - irlap_next_state(self, LAP_NRM_S); - } - } - } else if (nr_status == NR_UNEXPECTED) { - self->remote_busy = FALSE; - irlap_update_nr_received(self, info->nr); - irlap_resend_rejected_frames(self, RSP_FRAME); - - irlap_start_wd_timer(self, self->wd_timeout); - - /* Keep state */ - irlap_next_state(self, LAP_NRM_S); - } else { - pr_debug("%s(), invalid nr not implemented!\n", - __func__); - } - break; - case RECV_SNRM_CMD: - /* SNRM frame is not allowed to contain an I-field */ - if (!info) { - del_timer(&self->wd_timer); - pr_debug("%s(), received SNRM cmd\n", __func__); - irlap_next_state(self, LAP_RESET_CHECK); - - irlap_reset_indication(self); - } else { - pr_debug("%s(), SNRM frame contained an I-field!\n", - __func__); - - } - break; - case RECV_REJ_CMD: - irlap_update_nr_received(self, info->nr); - if (self->remote_busy) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, RSP_FRAME); - } else - irlap_resend_rejected_frames(self, RSP_FRAME); - irlap_start_wd_timer(self, self->wd_timeout); - break; - case RECV_SREJ_CMD: - irlap_update_nr_received(self, info->nr); - if (self->remote_busy) { - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, RSP_FRAME); - } else - irlap_resend_rejected_frame(self, RSP_FRAME); - irlap_start_wd_timer(self, self->wd_timeout); - break; - case WD_TIMER_EXPIRED: - /* - * Wait until retry_count * n matches negotiated threshold/ - * disconnect time (note 2 in IrLAP p. 82) - * - * Similar to irlap_state_nrm_p() -> FINAL_TIMER_EXPIRED - * Note : self->wd_timeout = (self->final_timeout * 2), - * which explain why we use (self->N2 / 2) here !!! - * Jean II - */ - pr_debug("%s(), retry_count = %d\n", __func__, - self->retry_count); - - if (self->retry_count < (self->N2 / 2)) { - /* No retry, just wait for primary */ - irlap_start_wd_timer(self, self->wd_timeout); - self->retry_count++; - - if((self->retry_count % (self->N1 / 2)) == 0) - irlap_status_indication(self, - STATUS_NO_ACTIVITY); - } else { - irlap_apply_default_connection_parameters(self); - - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - irlap_disconnect_indication(self, LAP_NO_RESPONSE); - } - break; - case RECV_DISC_CMD: - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - /* Send disconnect response */ - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_ua_response_frame(self, NULL); - - del_timer(&self->wd_timer); - irlap_flush_all_queues(self); - /* Set default link parameters */ - irlap_apply_default_connection_parameters(self); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - case RECV_DISCOVERY_XID_CMD: - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rr_frame(self, RSP_FRAME); - self->ack_required = TRUE; - irlap_start_wd_timer(self, self->wd_timeout); - irlap_next_state(self, LAP_NRM_S); - - break; - case RECV_TEST_CMD: - /* Remove test frame header (only LAP header in NRM) */ - skb_pull(skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); - - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_start_wd_timer(self, self->wd_timeout); - - /* Send response (info will be copied) */ - irlap_send_test_frame(self, self->caddr, info->daddr, skb); - break; - default: - pr_debug("%s(), Unknown event %d, (%s)\n", __func__, - event, irlap_event[event]); - - ret = -EINVAL; - break; - } - return ret; -} - -/* - * Function irlap_state_sclose (self, event, skb, info) - */ -static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) -{ - IRDA_ASSERT(self != NULL, return -ENODEV;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); - - switch (event) { - case RECV_DISC_CMD: - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - /* Send disconnect response */ - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_ua_response_frame(self, NULL); - - del_timer(&self->wd_timer); - /* Set default link parameters */ - irlap_apply_default_connection_parameters(self); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - case RECV_DM_RSP: - /* IrLAP-1.1 p.82: in SCLOSE, S and I type RSP frames - * shall take us down into default NDM state, like DM_RSP - */ - case RECV_RR_RSP: - case RECV_RNR_RSP: - case RECV_REJ_RSP: - case RECV_SREJ_RSP: - case RECV_I_RSP: - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - del_timer(&self->wd_timer); - irlap_apply_default_connection_parameters(self); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - case WD_TIMER_EXPIRED: - /* Always switch state before calling upper layers */ - irlap_next_state(self, LAP_NDM); - - irlap_apply_default_connection_parameters(self); - - irlap_disconnect_indication(self, LAP_DISC_INDICATION); - break; - default: - /* IrLAP-1.1 p.82: in SCLOSE, basically any received frame - * with pf=1 shall restart the wd-timer and resend the rd:rsp - */ - if (info != NULL && info->pf) { - del_timer(&self->wd_timer); - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rd_frame(self); - irlap_start_wd_timer(self, self->wd_timeout); - break; /* stay in SCLOSE */ - } - - pr_debug("%s(), Unknown event %d, (%s)\n", __func__, - event, irlap_event[event]); - - break; - } - - return -1; -} - -static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, - struct irlap_info *info) -{ - int ret = 0; - - pr_debug("%s(), event=%s\n", __func__, irlap_event[event]); - - IRDA_ASSERT(self != NULL, return -ENODEV;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); - - switch (event) { - case RESET_RESPONSE: - irlap_send_ua_response_frame(self, &self->qos_rx); - irlap_initiate_connection_state(self); - irlap_start_wd_timer(self, WD_TIMEOUT); - irlap_flush_all_queues(self); - - irlap_next_state(self, LAP_NRM_S); - break; - case DISCONNECT_REQUEST: - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_send_rd_frame(self); - irlap_start_wd_timer(self, WD_TIMEOUT); - irlap_next_state(self, LAP_SCLOSE); - break; - default: - pr_debug("%s(), Unknown event %d, (%s)\n", __func__, - event, irlap_event[event]); - - ret = -EINVAL; - break; - } - return ret; -} diff --git a/drivers/staging/irda/net/irlap_frame.c b/drivers/staging/irda/net/irlap_frame.c deleted file mode 100644 index debda3de4726..000000000000 --- a/drivers/staging/irda/net/irlap_frame.c +++ /dev/null @@ -1,1407 +0,0 @@ -/********************************************************************* - * - * Filename: irlap_frame.c - * Version: 1.0 - * Description: Build and transmit IrLAP frames - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Aug 19 10:27:26 1997 - * Modified at: Wed Jan 5 08:59:04 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/skbuff.h> -#include <linux/if.h> -#include <linux/if_ether.h> -#include <linux/netdevice.h> -#include <linux/irda.h> -#include <linux/slab.h> - -#include <net/pkt_sched.h> -#include <net/sock.h> - -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> -#include <net/irda/irlap.h> -#include <net/irda/wrapper.h> -#include <net/irda/timer.h> -#include <net/irda/irlap_frame.h> -#include <net/irda/qos.h> - -static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, - int command); - -/* - * Function irlap_insert_info (self, skb) - * - * Insert minimum turnaround time and speed information into the skb. We - * need to do this since it's per packet relevant information. Safe to - * have this function inlined since it's only called from one place - */ -static inline void irlap_insert_info(struct irlap_cb *self, - struct sk_buff *skb) -{ - struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; - - /* - * Insert MTT (min. turn time) and speed into skb, so that the - * device driver knows which settings to use - */ - cb->magic = LAP_MAGIC; - cb->mtt = self->mtt_required; - cb->next_speed = self->speed; - - /* Reset */ - self->mtt_required = 0; - - /* - * Delay equals negotiated BOFs count, plus the number of BOFs to - * force the negotiated minimum turnaround time - */ - cb->xbofs = self->bofs_count; - cb->next_xbofs = self->next_bofs; - cb->xbofs_delay = self->xbofs_delay; - - /* Reset XBOF's delay (used only for getting min turn time) */ - self->xbofs_delay = 0; - /* Put the correct xbofs value for the next packet */ - self->bofs_count = self->next_bofs; -} - -/* - * Function irlap_queue_xmit (self, skb) - * - * A little wrapper for dev_queue_xmit, so we can insert some common - * code into it. - */ -void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb) -{ - /* Some common init stuff */ - skb->dev = self->netdev; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - skb->protocol = htons(ETH_P_IRDA); - skb->priority = TC_PRIO_BESTEFFORT; - - irlap_insert_info(self, skb); - - if (unlikely(self->mode & IRDA_MODE_MONITOR)) { - pr_debug("%s(): %s is in monitor mode\n", __func__, - self->netdev->name); - dev_kfree_skb(skb); - return; - } - - dev_queue_xmit(skb); -} - -/* - * Function irlap_send_snrm_cmd (void) - * - * Transmits a connect SNRM command frame - */ -void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) -{ - struct sk_buff *tx_skb; - struct snrm_frame *frame; - int ret; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Allocate frame */ - tx_skb = alloc_skb(sizeof(struct snrm_frame) + - IRLAP_NEGOCIATION_PARAMS_LEN, - GFP_ATOMIC); - if (!tx_skb) - return; - - frame = skb_put(tx_skb, 2); - - /* Insert connection address field */ - if (qos) - frame->caddr = CMD_FRAME | CBROADCAST; - else - frame->caddr = CMD_FRAME | self->caddr; - - /* Insert control field */ - frame->control = SNRM_CMD | PF_BIT; - - /* - * If we are establishing a connection then insert QoS parameters - */ - if (qos) { - skb_put(tx_skb, 9); /* 25 left */ - frame->saddr = cpu_to_le32(self->saddr); - frame->daddr = cpu_to_le32(self->daddr); - - frame->ncaddr = self->caddr; - - ret = irlap_insert_qos_negotiation_params(self, tx_skb); - if (ret < 0) { - dev_kfree_skb(tx_skb); - return; - } - } - irlap_queue_xmit(self, tx_skb); -} - -/* - * Function irlap_recv_snrm_cmd (skb, info) - * - * Received SNRM (Set Normal Response Mode) command frame - * - */ -static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info) -{ - struct snrm_frame *frame; - - if (pskb_may_pull(skb,sizeof(struct snrm_frame))) { - frame = (struct snrm_frame *) skb->data; - - /* Copy the new connection address ignoring the C/R bit */ - info->caddr = frame->ncaddr & 0xFE; - - /* Check if the new connection address is valid */ - if ((info->caddr == 0x00) || (info->caddr == 0xfe)) { - pr_debug("%s(), invalid connection address!\n", - __func__); - return; - } - - /* Copy peer device address */ - info->daddr = le32_to_cpu(frame->saddr); - info->saddr = le32_to_cpu(frame->daddr); - - /* Only accept if addressed directly to us */ - if (info->saddr != self->saddr) { - pr_debug("%s(), not addressed to us!\n", - __func__); - return; - } - irlap_do_event(self, RECV_SNRM_CMD, skb, info); - } else { - /* Signal that this SNRM frame does not contain and I-field */ - irlap_do_event(self, RECV_SNRM_CMD, skb, NULL); - } -} - -/* - * Function irlap_send_ua_response_frame (qos) - * - * Send UA (Unnumbered Acknowledgement) frame - * - */ -void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) -{ - struct sk_buff *tx_skb; - struct ua_frame *frame; - int ret; - - pr_debug("%s() <%ld>\n", __func__, jiffies); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Allocate frame */ - tx_skb = alloc_skb(sizeof(struct ua_frame) + - IRLAP_NEGOCIATION_PARAMS_LEN, - GFP_ATOMIC); - if (!tx_skb) - return; - - frame = skb_put(tx_skb, 10); - - /* Build UA response */ - frame->caddr = self->caddr; - frame->control = UA_RSP | PF_BIT; - - frame->saddr = cpu_to_le32(self->saddr); - frame->daddr = cpu_to_le32(self->daddr); - - /* Should we send QoS negotiation parameters? */ - if (qos) { - ret = irlap_insert_qos_negotiation_params(self, tx_skb); - if (ret < 0) { - dev_kfree_skb(tx_skb); - return; - } - } - - irlap_queue_xmit(self, tx_skb); -} - - -/* - * Function irlap_send_dm_frame (void) - * - * Send disconnected mode (DM) frame - * - */ -void irlap_send_dm_frame( struct irlap_cb *self) -{ - struct sk_buff *tx_skb = NULL; - struct dm_frame *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - tx_skb = alloc_skb(sizeof(struct dm_frame), GFP_ATOMIC); - if (!tx_skb) - return; - - frame = skb_put(tx_skb, 2); - - if (self->state == LAP_NDM) - frame->caddr = CBROADCAST; - else - frame->caddr = self->caddr; - - frame->control = DM_RSP | PF_BIT; - - irlap_queue_xmit(self, tx_skb); -} - -/* - * Function irlap_send_disc_frame (void) - * - * Send disconnect (DISC) frame - * - */ -void irlap_send_disc_frame(struct irlap_cb *self) -{ - struct sk_buff *tx_skb = NULL; - struct disc_frame *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - tx_skb = alloc_skb(sizeof(struct disc_frame), GFP_ATOMIC); - if (!tx_skb) - return; - - frame = skb_put(tx_skb, 2); - - frame->caddr = self->caddr | CMD_FRAME; - frame->control = DISC_CMD | PF_BIT; - - irlap_queue_xmit(self, tx_skb); -} - -/* - * Function irlap_send_discovery_xid_frame (S, s, command) - * - * Build and transmit a XID (eXchange station IDentifier) discovery - * frame. - */ -void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, - __u8 command, discovery_t *discovery) -{ - struct sk_buff *tx_skb = NULL; - struct xid_frame *frame; - __u32 bcast = BROADCAST; - __u8 *info; - - pr_debug("%s(), s=%d, S=%d, command=%d\n", __func__, - s, S, command); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(discovery != NULL, return;); - - tx_skb = alloc_skb(sizeof(struct xid_frame) + IRLAP_DISCOVERY_INFO_LEN, - GFP_ATOMIC); - if (!tx_skb) - return; - - skb_put(tx_skb, 14); - frame = (struct xid_frame *) tx_skb->data; - - if (command) { - frame->caddr = CBROADCAST | CMD_FRAME; - frame->control = XID_CMD | PF_BIT; - } else { - frame->caddr = CBROADCAST; - frame->control = XID_RSP | PF_BIT; - } - frame->ident = XID_FORMAT; - - frame->saddr = cpu_to_le32(self->saddr); - - if (command) - frame->daddr = cpu_to_le32(bcast); - else - frame->daddr = cpu_to_le32(discovery->data.daddr); - - switch (S) { - case 1: - frame->flags = 0x00; - break; - case 6: - frame->flags = 0x01; - break; - case 8: - frame->flags = 0x02; - break; - case 16: - frame->flags = 0x03; - break; - default: - frame->flags = 0x02; - break; - } - - frame->slotnr = s; - frame->version = 0x00; - - /* - * Provide info for final slot only in commands, and for all - * responses. Send the second byte of the hint only if the - * EXTENSION bit is set in the first byte. - */ - if (!command || (frame->slotnr == 0xff)) { - int len; - - if (discovery->data.hints[0] & HINT_EXTENSION) { - info = skb_put(tx_skb, 2); - info[0] = discovery->data.hints[0]; - info[1] = discovery->data.hints[1]; - } else { - info = skb_put(tx_skb, 1); - info[0] = discovery->data.hints[0]; - } - info = skb_put(tx_skb, 1); - info[0] = discovery->data.charset; - - len = IRDA_MIN(discovery->name_len, skb_tailroom(tx_skb)); - skb_put_data(tx_skb, discovery->data.info, len); - } - irlap_queue_xmit(self, tx_skb); -} - -/* - * Function irlap_recv_discovery_xid_rsp (skb, info) - * - * Received a XID discovery response - * - */ -static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, - struct sk_buff *skb, - struct irlap_info *info) -{ - struct xid_frame *xid; - discovery_t *discovery = NULL; - __u8 *discovery_info; - char *text; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { - net_err_ratelimited("%s: frame too short!\n", __func__); - return; - } - - xid = (struct xid_frame *) skb->data; - - info->daddr = le32_to_cpu(xid->saddr); - info->saddr = le32_to_cpu(xid->daddr); - - /* Make sure frame is addressed to us */ - if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { - pr_debug("%s(), frame is not addressed to us!\n", - __func__); - return; - } - - if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) { - net_warn_ratelimited("%s: kmalloc failed!\n", __func__); - return; - } - - discovery->data.daddr = info->daddr; - discovery->data.saddr = self->saddr; - discovery->timestamp = jiffies; - - pr_debug("%s(), daddr=%08x\n", __func__, - discovery->data.daddr); - - discovery_info = skb_pull(skb, sizeof(struct xid_frame)); - - /* Get info returned from peer */ - discovery->data.hints[0] = discovery_info[0]; - if (discovery_info[0] & HINT_EXTENSION) { - pr_debug("EXTENSION\n"); - discovery->data.hints[1] = discovery_info[1]; - discovery->data.charset = discovery_info[2]; - text = (char *) &discovery_info[3]; - } else { - discovery->data.hints[1] = 0; - discovery->data.charset = discovery_info[1]; - text = (char *) &discovery_info[2]; - } - /* - * Terminate info string, should be safe since this is where the - * FCS bytes resides. - */ - skb->data[skb->len] = '\0'; - strncpy(discovery->data.info, text, NICKNAME_MAX_LEN); - discovery->name_len = strlen(discovery->data.info); - - info->discovery = discovery; - - irlap_do_event(self, RECV_DISCOVERY_XID_RSP, skb, info); -} - -/* - * Function irlap_recv_discovery_xid_cmd (skb, info) - * - * Received a XID discovery command - * - */ -static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, - struct sk_buff *skb, - struct irlap_info *info) -{ - struct xid_frame *xid; - discovery_t *discovery = NULL; - __u8 *discovery_info; - char *text; - - if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { - net_err_ratelimited("%s: frame too short!\n", __func__); - return; - } - - xid = (struct xid_frame *) skb->data; - - info->daddr = le32_to_cpu(xid->saddr); - info->saddr = le32_to_cpu(xid->daddr); - - /* Make sure frame is addressed to us */ - if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { - pr_debug("%s(), frame is not addressed to us!\n", - __func__); - return; - } - - switch (xid->flags & 0x03) { - case 0x00: - info->S = 1; - break; - case 0x01: - info->S = 6; - break; - case 0x02: - info->S = 8; - break; - case 0x03: - info->S = 16; - break; - default: - /* Error!! */ - return; - } - info->s = xid->slotnr; - - discovery_info = skb_pull(skb, sizeof(struct xid_frame)); - - /* - * Check if last frame - */ - if (info->s == 0xff) { - /* Check if things are sane at this point... */ - if((discovery_info == NULL) || - !pskb_may_pull(skb, 3)) { - net_err_ratelimited("%s: discovery frame too short!\n", - __func__); - return; - } - - /* - * We now have some discovery info to deliver! - */ - discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC); - if (!discovery) - return; - - discovery->data.daddr = info->daddr; - discovery->data.saddr = self->saddr; - discovery->timestamp = jiffies; - - discovery->data.hints[0] = discovery_info[0]; - if (discovery_info[0] & HINT_EXTENSION) { - discovery->data.hints[1] = discovery_info[1]; - discovery->data.charset = discovery_info[2]; - text = (char *) &discovery_info[3]; - } else { - discovery->data.hints[1] = 0; - discovery->data.charset = discovery_info[1]; - text = (char *) &discovery_info[2]; - } - /* - * Terminate string, should be safe since this is where the - * FCS bytes resides. - */ - skb->data[skb->len] = '\0'; - strncpy(discovery->data.info, text, NICKNAME_MAX_LEN); - discovery->name_len = strlen(discovery->data.info); - - info->discovery = discovery; - } else - info->discovery = NULL; - - irlap_do_event(self, RECV_DISCOVERY_XID_CMD, skb, info); -} - -/* - * Function irlap_send_rr_frame (self, command) - * - * Build and transmit RR (Receive Ready) frame. Notice that it is currently - * only possible to send RR frames with the poll bit set. - */ -void irlap_send_rr_frame(struct irlap_cb *self, int command) -{ - struct sk_buff *tx_skb; - struct rr_frame *frame; - - tx_skb = alloc_skb(sizeof(struct rr_frame), GFP_ATOMIC); - if (!tx_skb) - return; - - frame = skb_put(tx_skb, 2); - - frame->caddr = self->caddr; - frame->caddr |= (command) ? CMD_FRAME : 0; - - frame->control = RR | PF_BIT | (self->vr << 5); - - irlap_queue_xmit(self, tx_skb); -} - -/* - * Function irlap_send_rd_frame (self) - * - * Request disconnect. Used by a secondary station to request the - * disconnection of the link. - */ -void irlap_send_rd_frame(struct irlap_cb *self) -{ - struct sk_buff *tx_skb; - struct rd_frame *frame; - - tx_skb = alloc_skb(sizeof(struct rd_frame), GFP_ATOMIC); - if (!tx_skb) - return; - - frame = skb_put(tx_skb, 2); - - frame->caddr = self->caddr; - frame->control = RD_RSP | PF_BIT; - - irlap_queue_xmit(self, tx_skb); -} - -/* - * Function irlap_recv_rr_frame (skb, info) - * - * Received RR (Receive Ready) frame from peer station, no harm in - * making it inline since its called only from one single place - * (irlap_driver_rcv). - */ -static inline void irlap_recv_rr_frame(struct irlap_cb *self, - struct sk_buff *skb, - struct irlap_info *info, int command) -{ - info->nr = skb->data[1] >> 5; - - /* Check if this is a command or a response frame */ - if (command) - irlap_do_event(self, RECV_RR_CMD, skb, info); - else - irlap_do_event(self, RECV_RR_RSP, skb, info); -} - -/* - * Function irlap_recv_rnr_frame (self, skb, info) - * - * Received RNR (Receive Not Ready) frame from peer station - * - */ -static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info, int command) -{ - info->nr = skb->data[1] >> 5; - - pr_debug("%s(), nr=%d, %ld\n", __func__, info->nr, jiffies); - - if (command) - irlap_do_event(self, RECV_RNR_CMD, skb, info); - else - irlap_do_event(self, RECV_RNR_RSP, skb, info); -} - -static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info, int command) -{ - info->nr = skb->data[1] >> 5; - - /* Check if this is a command or a response frame */ - if (command) - irlap_do_event(self, RECV_REJ_CMD, skb, info); - else - irlap_do_event(self, RECV_REJ_RSP, skb, info); -} - -static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info, int command) -{ - info->nr = skb->data[1] >> 5; - - /* Check if this is a command or a response frame */ - if (command) - irlap_do_event(self, RECV_SREJ_CMD, skb, info); - else - irlap_do_event(self, RECV_SREJ_RSP, skb, info); -} - -static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info, int command) -{ - /* Check if this is a command or a response frame */ - if (command) - irlap_do_event(self, RECV_DISC_CMD, skb, info); - else - irlap_do_event(self, RECV_RD_RSP, skb, info); -} - -/* - * Function irlap_recv_ua_frame (skb, frame) - * - * Received UA (Unnumbered Acknowledgement) frame - * - */ -static inline void irlap_recv_ua_frame(struct irlap_cb *self, - struct sk_buff *skb, - struct irlap_info *info) -{ - irlap_do_event(self, RECV_UA_RSP, skb, info); -} - -/* - * Function irlap_send_data_primary(self, skb) - * - * Send I-frames as the primary station but without the poll bit set - * - */ -void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb) -{ - struct sk_buff *tx_skb; - - if (skb->data[1] == I_FRAME) { - - /* - * Insert frame sequence number (Vs) in control field before - * inserting into transmit window queue. - */ - skb->data[1] = I_FRAME | (self->vs << 1); - - /* - * Insert frame in store, in case of retransmissions - * Increase skb reference count, see irlap_do_event() - */ - skb_get(skb); - skb_queue_tail(&self->wx_list, skb); - - /* Copy buffer */ - tx_skb = skb_clone(skb, GFP_ATOMIC); - if (tx_skb == NULL) { - return; - } - - self->vs = (self->vs + 1) % 8; - self->ack_required = FALSE; - self->window -= 1; - - irlap_send_i_frame( self, tx_skb, CMD_FRAME); - } else { - pr_debug("%s(), sending unreliable frame\n", __func__); - irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); - self->window -= 1; - } -} -/* - * Function irlap_send_data_primary_poll (self, skb) - * - * Send I(nformation) frame as primary with poll bit set - */ -void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) -{ - struct sk_buff *tx_skb; - int transmission_time; - - /* Stop P timer */ - del_timer(&self->poll_timer); - - /* Is this reliable or unreliable data? */ - if (skb->data[1] == I_FRAME) { - - /* - * Insert frame sequence number (Vs) in control field before - * inserting into transmit window queue. - */ - skb->data[1] = I_FRAME | (self->vs << 1); - - /* - * Insert frame in store, in case of retransmissions - * Increase skb reference count, see irlap_do_event() - */ - skb_get(skb); - skb_queue_tail(&self->wx_list, skb); - - /* Copy buffer */ - tx_skb = skb_clone(skb, GFP_ATOMIC); - if (tx_skb == NULL) { - return; - } - - /* - * Set poll bit if necessary. We do this to the copied - * skb, since retransmitted need to set or clear the poll - * bit depending on when they are sent. - */ - tx_skb->data[1] |= PF_BIT; - - self->vs = (self->vs + 1) % 8; - self->ack_required = FALSE; - - irlap_next_state(self, LAP_NRM_P); - irlap_send_i_frame(self, tx_skb, CMD_FRAME); - } else { - pr_debug("%s(), sending unreliable frame\n", __func__); - - if (self->ack_required) { - irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); - irlap_next_state(self, LAP_NRM_P); - irlap_send_rr_frame(self, CMD_FRAME); - self->ack_required = FALSE; - } else { - skb->data[1] |= PF_BIT; - irlap_next_state(self, LAP_NRM_P); - irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); - } - } - - /* How much time we took for transmission of all frames. - * We don't know, so let assume we used the full window. Jean II */ - transmission_time = self->final_timeout; - - /* Reset parameter so that we can fill next window */ - self->window = self->window_size; - -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - /* Remove what we have not used. Just do a prorata of the - * bytes left in window to window capacity. - * See max_line_capacities[][] in qos.c for details. Jean II */ - transmission_time -= (self->final_timeout * self->bytes_left - / self->line_capacity); - pr_debug("%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", - __func__, self->final_timeout, self->bytes_left, - self->line_capacity, transmission_time); - - /* We are allowed to transmit a maximum number of bytes again. */ - self->bytes_left = self->line_capacity; -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - - /* - * The network layer has a intermediate buffer between IrLAP - * and the IrDA driver which can contain 8 frames. So, even - * though IrLAP is currently sending the *last* frame of the - * tx-window, the driver most likely has only just started - * sending the *first* frame of the same tx-window. - * I.e. we are always at the very beginning of or Tx window. - * Now, we are supposed to set the final timer from the end - * of our tx-window to let the other peer reply. So, we need - * to add extra time to compensate for the fact that we - * are really at the start of tx-window, otherwise the final timer - * might expire before he can answer... - * Jean II - */ - irlap_start_final_timer(self, self->final_timeout + transmission_time); - - /* - * The clever amongst you might ask why we do this adjustement - * only here, and not in all the other cases in irlap_event.c. - * In all those other case, we only send a very short management - * frame (few bytes), so the adjustement would be lost in the - * noise... - * The exception of course is irlap_resend_rejected_frame(). - * Jean II */ -} - -/* - * Function irlap_send_data_secondary_final (self, skb) - * - * Send I(nformation) frame as secondary with final bit set - * - */ -void irlap_send_data_secondary_final(struct irlap_cb *self, - struct sk_buff *skb) -{ - struct sk_buff *tx_skb = NULL; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - /* Is this reliable or unreliable data? */ - if (skb->data[1] == I_FRAME) { - - /* - * Insert frame sequence number (Vs) in control field before - * inserting into transmit window queue. - */ - skb->data[1] = I_FRAME | (self->vs << 1); - - /* - * Insert frame in store, in case of retransmissions - * Increase skb reference count, see irlap_do_event() - */ - skb_get(skb); - skb_queue_tail(&self->wx_list, skb); - - tx_skb = skb_clone(skb, GFP_ATOMIC); - if (tx_skb == NULL) { - return; - } - - tx_skb->data[1] |= PF_BIT; - - self->vs = (self->vs + 1) % 8; - self->ack_required = FALSE; - - irlap_send_i_frame(self, tx_skb, RSP_FRAME); - } else { - if (self->ack_required) { - irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); - irlap_send_rr_frame(self, RSP_FRAME); - self->ack_required = FALSE; - } else { - skb->data[1] |= PF_BIT; - irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); - } - } - - self->window = self->window_size; -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - /* We are allowed to transmit a maximum number of bytes again. */ - self->bytes_left = self->line_capacity; -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - - irlap_start_wd_timer(self, self->wd_timeout); -} - -/* - * Function irlap_send_data_secondary (self, skb) - * - * Send I(nformation) frame as secondary without final bit set - * - */ -void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) -{ - struct sk_buff *tx_skb = NULL; - - /* Is this reliable or unreliable data? */ - if (skb->data[1] == I_FRAME) { - - /* - * Insert frame sequence number (Vs) in control field before - * inserting into transmit window queue. - */ - skb->data[1] = I_FRAME | (self->vs << 1); - - /* - * Insert frame in store, in case of retransmissions - * Increase skb reference count, see irlap_do_event() - */ - skb_get(skb); - skb_queue_tail(&self->wx_list, skb); - - tx_skb = skb_clone(skb, GFP_ATOMIC); - if (tx_skb == NULL) { - return; - } - - self->vs = (self->vs + 1) % 8; - self->ack_required = FALSE; - self->window -= 1; - - irlap_send_i_frame(self, tx_skb, RSP_FRAME); - } else { - irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME); - self->window -= 1; - } -} - -/* - * Function irlap_resend_rejected_frames (nr) - * - * Resend frames which has not been acknowledged. Should be safe to - * traverse the list without locking it since this function will only be - * called from interrupt context (BH) - */ -void irlap_resend_rejected_frames(struct irlap_cb *self, int command) -{ - struct sk_buff *tx_skb; - struct sk_buff *skb; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Resend unacknowledged frame(s) */ - skb_queue_walk(&self->wx_list, skb) { - irlap_wait_min_turn_around(self, &self->qos_tx); - - /* We copy the skb to be retransmitted since we will have to - * modify it. Cloning will confuse packet sniffers - */ - /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ - tx_skb = skb_copy(skb, GFP_ATOMIC); - if (!tx_skb) { - pr_debug("%s(), unable to copy\n", __func__); - return; - } - - /* Clear old Nr field + poll bit */ - tx_skb->data[1] &= 0x0f; - - /* - * Set poll bit on the last frame retransmitted - */ - if (skb_queue_is_last(&self->wx_list, skb)) - tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ - else - tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */ - - irlap_send_i_frame(self, tx_skb, command); - } -#if 0 /* Not yet */ - /* - * We can now fill the window with additional data frames - */ - while (!skb_queue_empty(&self->txq)) { - - pr_debug("%s(), sending additional frames!\n", __func__); - if (self->window > 0) { - skb = skb_dequeue( &self->txq); - IRDA_ASSERT(skb != NULL, return;); - - /* - * If send window > 1 then send frame with pf - * bit cleared - */ - if ((self->window > 1) && - !skb_queue_empty(&self->txq)) { - irlap_send_data_primary(self, skb); - } else { - irlap_send_data_primary_poll(self, skb); - } - kfree_skb(skb); - } - } -#endif -} - -void irlap_resend_rejected_frame(struct irlap_cb *self, int command) -{ - struct sk_buff *tx_skb; - struct sk_buff *skb; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - /* Resend unacknowledged frame(s) */ - skb = skb_peek(&self->wx_list); - if (skb != NULL) { - irlap_wait_min_turn_around(self, &self->qos_tx); - - /* We copy the skb to be retransmitted since we will have to - * modify it. Cloning will confuse packet sniffers - */ - /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ - tx_skb = skb_copy(skb, GFP_ATOMIC); - if (!tx_skb) { - pr_debug("%s(), unable to copy\n", __func__); - return; - } - - /* Clear old Nr field + poll bit */ - tx_skb->data[1] &= 0x0f; - - /* Set poll/final bit */ - tx_skb->data[1] |= PF_BIT; /* Set p/f bit */ - - irlap_send_i_frame(self, tx_skb, command); - } -} - -/* - * Function irlap_send_ui_frame (self, skb, command) - * - * Contruct and transmit an Unnumbered Information (UI) frame - * - */ -void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, - __u8 caddr, int command) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - /* Insert connection address */ - skb->data[0] = caddr | ((command) ? CMD_FRAME : 0); - - irlap_queue_xmit(self, skb); -} - -/* - * Function irlap_send_i_frame (skb) - * - * Contruct and transmit Information (I) frame - */ -static void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, - int command) -{ - /* Insert connection address */ - skb->data[0] = self->caddr; - skb->data[0] |= (command) ? CMD_FRAME : 0; - - /* Insert next to receive (Vr) */ - skb->data[1] |= (self->vr << 5); /* insert nr */ - - irlap_queue_xmit(self, skb); -} - -/* - * Function irlap_recv_i_frame (skb, frame) - * - * Receive and parse an I (Information) frame, no harm in making it inline - * since it's called only from one single place (irlap_driver_rcv). - */ -static inline void irlap_recv_i_frame(struct irlap_cb *self, - struct sk_buff *skb, - struct irlap_info *info, int command) -{ - info->nr = skb->data[1] >> 5; /* Next to receive */ - info->pf = skb->data[1] & PF_BIT; /* Final bit */ - info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */ - - /* Check if this is a command or a response frame */ - if (command) - irlap_do_event(self, RECV_I_CMD, skb, info); - else - irlap_do_event(self, RECV_I_RSP, skb, info); -} - -/* - * Function irlap_recv_ui_frame (self, skb, info) - * - * Receive and parse an Unnumbered Information (UI) frame - * - */ -static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info) -{ - info->pf = skb->data[1] & PF_BIT; /* Final bit */ - - irlap_do_event(self, RECV_UI_FRAME, skb, info); -} - -/* - * Function irlap_recv_frmr_frame (skb, frame) - * - * Received Frame Reject response. - * - */ -static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info) -{ - __u8 *frame; - int w, x, y, z; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(info != NULL, return;); - - if (!pskb_may_pull(skb, 4)) { - net_err_ratelimited("%s: frame too short!\n", __func__); - return; - } - - frame = skb->data; - - info->nr = frame[2] >> 5; /* Next to receive */ - info->pf = frame[2] & PF_BIT; /* Final bit */ - info->ns = (frame[2] >> 1) & 0x07; /* Next to send */ - - w = frame[3] & 0x01; - x = frame[3] & 0x02; - y = frame[3] & 0x04; - z = frame[3] & 0x08; - - if (w) { - pr_debug("Rejected control field is undefined or not implemented\n"); - } - if (x) { - pr_debug("Rejected control field was invalid because it contained a non permitted I field\n"); - } - if (y) { - pr_debug("Received I field exceeded the maximum negotiated for the existing connection or exceeded the maximum this station supports if no connection exists\n"); - } - if (z) { - pr_debug("Rejected control field control field contained an invalid Nr count\n"); - } - irlap_do_event(self, RECV_FRMR_RSP, skb, info); -} - -/* - * Function irlap_send_test_frame (self, daddr) - * - * Send a test frame response - * - */ -void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, - struct sk_buff *cmd) -{ - struct sk_buff *tx_skb; - struct test_frame *frame; - - tx_skb = alloc_skb(cmd->len + sizeof(struct test_frame), GFP_ATOMIC); - if (!tx_skb) - return; - - /* Broadcast frames must include saddr and daddr fields */ - if (caddr == CBROADCAST) { - frame = skb_put(tx_skb, sizeof(struct test_frame)); - - /* Insert the swapped addresses */ - frame->saddr = cpu_to_le32(self->saddr); - frame->daddr = cpu_to_le32(daddr); - } else - frame = skb_put(tx_skb, LAP_ADDR_HEADER + LAP_CTRL_HEADER); - - frame->caddr = caddr; - frame->control = TEST_RSP | PF_BIT; - - /* Copy info */ - skb_put_data(tx_skb, cmd->data, cmd->len); - - /* Return to sender */ - irlap_wait_min_turn_around(self, &self->qos_tx); - irlap_queue_xmit(self, tx_skb); -} - -/* - * Function irlap_recv_test_frame (self, skb) - * - * Receive a test frame - * - */ -static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, - struct irlap_info *info, int command) -{ - struct test_frame *frame; - - if (!pskb_may_pull(skb, sizeof(*frame))) { - net_err_ratelimited("%s: frame too short!\n", __func__); - return; - } - frame = (struct test_frame *) skb->data; - - /* Broadcast frames must carry saddr and daddr fields */ - if (info->caddr == CBROADCAST) { - if (skb->len < sizeof(struct test_frame)) { - pr_debug("%s() test frame too short!\n", - __func__); - return; - } - - /* Read and swap addresses */ - info->daddr = le32_to_cpu(frame->saddr); - info->saddr = le32_to_cpu(frame->daddr); - - /* Make sure frame is addressed to us */ - if ((info->saddr != self->saddr) && - (info->saddr != BROADCAST)) { - return; - } - } - - if (command) - irlap_do_event(self, RECV_TEST_CMD, skb, info); - else - irlap_do_event(self, RECV_TEST_RSP, skb, info); -} - -/* - * Function irlap_driver_rcv (skb, netdev, ptype) - * - * Called when a frame is received. Dispatches the right receive function - * for processing of the frame. - * - * Note on skb management : - * After calling the higher layers of the IrDA stack, we always - * kfree() the skb, which drop the reference count (and potentially - * destroy it). - * If a higher layer of the stack want to keep the skb around (to put - * in a queue or pass it to the higher layer), it will need to use - * skb_get() to keep a reference on it. This is usually done at the - * LMP level in irlmp.c. - * Jean II - */ -int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *orig_dev) -{ - struct irlap_info info; - struct irlap_cb *self; - int command; - __u8 control; - int ret = -1; - - if (!net_eq(dev_net(dev), &init_net)) - goto out; - - /* FIXME: should we get our own field? */ - self = (struct irlap_cb *) dev->atalk_ptr; - - /* If the net device is down, then IrLAP is gone! */ - if (!self || self->magic != LAP_MAGIC) - goto err; - - /* We are no longer an "old" protocol, so we need to handle - * share and non linear skbs. This should never happen, so - * we don't need to be clever about it. Jean II */ - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - net_err_ratelimited("%s: can't clone shared skb!\n", __func__); - goto err; - } - - /* Check if frame is large enough for parsing */ - if (!pskb_may_pull(skb, 2)) { - net_err_ratelimited("%s: frame too short!\n", __func__); - goto err; - } - - command = skb->data[0] & CMD_FRAME; - info.caddr = skb->data[0] & CBROADCAST; - - info.pf = skb->data[1] & PF_BIT; - info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */ - - control = info.control; - - /* First we check if this frame has a valid connection address */ - if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) { - pr_debug("%s(), wrong connection address!\n", - __func__); - goto out; - } - /* - * Optimize for the common case and check if the frame is an - * I(nformation) frame. Only I-frames have bit 0 set to 0 - */ - if (~control & 0x01) { - irlap_recv_i_frame(self, skb, &info, command); - goto out; - } - /* - * We now check is the frame is an S(upervisory) frame. Only - * S-frames have bit 0 set to 1 and bit 1 set to 0 - */ - if (~control & 0x02) { - /* - * Received S(upervisory) frame, check which frame type it is - * only the first nibble is of interest - */ - switch (control & 0x0f) { - case RR: - irlap_recv_rr_frame(self, skb, &info, command); - break; - case RNR: - irlap_recv_rnr_frame(self, skb, &info, command); - break; - case REJ: - irlap_recv_rej_frame(self, skb, &info, command); - break; - case SREJ: - irlap_recv_srej_frame(self, skb, &info, command); - break; - default: - net_warn_ratelimited("%s: Unknown S-frame %02x received!\n", - __func__, info.control); - break; - } - goto out; - } - /* - * This must be a C(ontrol) frame - */ - switch (control) { - case XID_RSP: - irlap_recv_discovery_xid_rsp(self, skb, &info); - break; - case XID_CMD: - irlap_recv_discovery_xid_cmd(self, skb, &info); - break; - case SNRM_CMD: - irlap_recv_snrm_cmd(self, skb, &info); - break; - case DM_RSP: - irlap_do_event(self, RECV_DM_RSP, skb, &info); - break; - case DISC_CMD: /* And RD_RSP since they have the same value */ - irlap_recv_disc_frame(self, skb, &info, command); - break; - case TEST_CMD: - irlap_recv_test_frame(self, skb, &info, command); - break; - case UA_RSP: - irlap_recv_ua_frame(self, skb, &info); - break; - case FRMR_RSP: - irlap_recv_frmr_frame(self, skb, &info); - break; - case UI_FRAME: - irlap_recv_ui_frame(self, skb, &info); - break; - default: - net_warn_ratelimited("%s: Unknown frame %02x received!\n", - __func__, info.control); - break; - } -out: - ret = 0; -err: - /* Always drop our reference on the skb */ - dev_kfree_skb(skb); - return ret; -} diff --git a/drivers/staging/irda/net/irlmp.c b/drivers/staging/irda/net/irlmp.c deleted file mode 100644 index 7af618fb66c0..000000000000 --- a/drivers/staging/irda/net/irlmp.c +++ /dev/null @@ -1,1996 +0,0 @@ -/********************************************************************* - * - * Filename: irlmp.c - * Version: 1.0 - * Description: IrDA Link Management Protocol (LMP) layer - * Status: Stable. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 17 20:54:32 1997 - * Modified at: Wed Jan 5 11:26:03 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/skbuff.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/kmod.h> -#include <linux/random.h> -#include <linux/seq_file.h> - -#include <net/irda/irda.h> -#include <net/irda/timer.h> -#include <net/irda/qos.h> -#include <net/irda/irlap.h> -#include <net/irda/iriap.h> -#include <net/irda/irlmp.h> -#include <net/irda/irlmp_frame.h> - -#include <asm/unaligned.h> - -static __u8 irlmp_find_free_slsap(void); -static int irlmp_slsap_inuse(__u8 slsap_sel); - -/* Master structure */ -struct irlmp_cb *irlmp = NULL; - -/* These can be altered by the sysctl interface */ -int sysctl_discovery = 0; -int sysctl_discovery_timeout = 3; /* 3 seconds by default */ -int sysctl_discovery_slots = 6; /* 6 slots by default */ -int sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ; -char sysctl_devname[65]; - -static const char *irlmp_reasons[] = { - "ERROR, NOT USED", - "LM_USER_REQUEST", - "LM_LAP_DISCONNECT", - "LM_CONNECT_FAILURE", - "LM_LAP_RESET", - "LM_INIT_DISCONNECT", - "ERROR, NOT USED", - "UNKNOWN", -}; - -const char *irlmp_reason_str(LM_REASON reason) -{ - reason = min_t(size_t, reason, ARRAY_SIZE(irlmp_reasons) - 1); - return irlmp_reasons[reason]; -} - -/* - * Function irlmp_init (void) - * - * Create (allocate) the main IrLMP structure - * - */ -int __init irlmp_init(void) -{ - /* Initialize the irlmp structure. */ - irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL); - if (irlmp == NULL) - return -ENOMEM; - - irlmp->magic = LMP_MAGIC; - - irlmp->clients = hashbin_new(HB_LOCK); - irlmp->services = hashbin_new(HB_LOCK); - irlmp->links = hashbin_new(HB_LOCK); - irlmp->unconnected_lsaps = hashbin_new(HB_LOCK); - irlmp->cachelog = hashbin_new(HB_NOLOCK); - - if ((irlmp->clients == NULL) || - (irlmp->services == NULL) || - (irlmp->links == NULL) || - (irlmp->unconnected_lsaps == NULL) || - (irlmp->cachelog == NULL)) { - return -ENOMEM; - } - - spin_lock_init(&irlmp->cachelog->hb_spinlock); - - irlmp->last_lsap_sel = 0x0f; /* Reserved 0x00-0x0f */ - strcpy(sysctl_devname, "Linux"); - - timer_setup(&irlmp->discovery_timer, NULL, 0); - - /* Do discovery every 3 seconds, conditionally */ - if (sysctl_discovery) - irlmp_start_discovery_timer(irlmp, - sysctl_discovery_timeout*HZ); - - return 0; -} - -/* - * Function irlmp_cleanup (void) - * - * Remove IrLMP layer - * - */ -void irlmp_cleanup(void) -{ - /* Check for main structure */ - IRDA_ASSERT(irlmp != NULL, return;); - IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;); - - del_timer(&irlmp->discovery_timer); - - hashbin_delete(irlmp->links, (FREE_FUNC) kfree); - hashbin_delete(irlmp->unconnected_lsaps, (FREE_FUNC) kfree); - hashbin_delete(irlmp->clients, (FREE_FUNC) kfree); - hashbin_delete(irlmp->services, (FREE_FUNC) kfree); - hashbin_delete(irlmp->cachelog, (FREE_FUNC) kfree); - - /* De-allocate main structure */ - kfree(irlmp); - irlmp = NULL; -} - -/* - * Function irlmp_open_lsap (slsap, notify) - * - * Register with IrLMP and create a local LSAP, - * returns handle to LSAP. - */ -struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid) -{ - struct lsap_cb *self; - - IRDA_ASSERT(notify != NULL, return NULL;); - IRDA_ASSERT(irlmp != NULL, return NULL;); - IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return NULL;); - IRDA_ASSERT(notify->instance != NULL, return NULL;); - - /* Does the client care which Source LSAP selector it gets? */ - if (slsap_sel == LSAP_ANY) { - slsap_sel = irlmp_find_free_slsap(); - if (!slsap_sel) - return NULL; - } else if (irlmp_slsap_inuse(slsap_sel)) - return NULL; - - /* Allocate new instance of a LSAP connection */ - self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC); - if (self == NULL) - return NULL; - - self->magic = LMP_LSAP_MAGIC; - self->slsap_sel = slsap_sel; - - /* Fix connectionless LSAP's */ - if (slsap_sel == LSAP_CONNLESS) { -#ifdef CONFIG_IRDA_ULTRA - self->dlsap_sel = LSAP_CONNLESS; - self->pid = pid; -#endif /* CONFIG_IRDA_ULTRA */ - } else - self->dlsap_sel = LSAP_ANY; - /* self->connected = FALSE; -> already NULL via memset() */ - - timer_setup(&self->watchdog_timer, NULL, 0); - - self->notify = *notify; - - self->lsap_state = LSAP_DISCONNECTED; - - /* Insert into queue of unconnected LSAPs */ - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, - (long) self, NULL); - - return self; -} -EXPORT_SYMBOL(irlmp_open_lsap); - -/* - * Function __irlmp_close_lsap (self) - * - * Remove an instance of LSAP - */ -static void __irlmp_close_lsap(struct lsap_cb *self) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - - /* - * Set some of the variables to preset values - */ - self->magic = 0; - del_timer(&self->watchdog_timer); /* Important! */ - - if (self->conn_skb) - dev_kfree_skb(self->conn_skb); - - kfree(self); -} - -/* - * Function irlmp_close_lsap (self) - * - * Close and remove LSAP - * - */ -void irlmp_close_lsap(struct lsap_cb *self) -{ - struct lap_cb *lap; - struct lsap_cb *lsap = NULL; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - - /* - * Find out if we should remove this LSAP from a link or from the - * list of unconnected lsaps (not associated with a link) - */ - lap = self->lap; - if (lap) { - IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); - /* We might close a LSAP before it has completed the - * connection setup. In those case, higher layers won't - * send a proper disconnect request. Harmless, except - * that we will forget to close LAP... - Jean II */ - if(self->lsap_state != LSAP_DISCONNECTED) { - self->lsap_state = LSAP_DISCONNECTED; - irlmp_do_lap_event(self->lap, - LM_LAP_DISCONNECT_REQUEST, NULL); - } - /* Now, remove from the link */ - lsap = hashbin_remove(lap->lsaps, (long) self, NULL); -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - lap->cache.valid = FALSE; -#endif - } - self->lap = NULL; - /* Check if we found the LSAP! If not then try the unconnected lsaps */ - if (!lsap) { - lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, - NULL); - } - if (!lsap) { - pr_debug("%s(), Looks like somebody has removed me already!\n", - __func__); - return; - } - __irlmp_close_lsap(self); -} -EXPORT_SYMBOL(irlmp_close_lsap); - -/* - * Function irlmp_register_irlap (saddr, notify) - * - * Register IrLAP layer with IrLMP. There is possible to have multiple - * instances of the IrLAP layer, each connected to different IrDA ports - * - */ -void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify) -{ - struct lap_cb *lap; - - IRDA_ASSERT(irlmp != NULL, return;); - IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return;); - IRDA_ASSERT(notify != NULL, return;); - - /* - * Allocate new instance of a LSAP connection - */ - lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL); - if (lap == NULL) - return; - - lap->irlap = irlap; - lap->magic = LMP_LAP_MAGIC; - lap->saddr = saddr; - lap->daddr = DEV_ADDR_ANY; -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - lap->cache.valid = FALSE; -#endif - lap->lsaps = hashbin_new(HB_LOCK); - if (lap->lsaps == NULL) { - net_warn_ratelimited("%s(), unable to kmalloc lsaps\n", - __func__); - kfree(lap); - return; - } - - lap->lap_state = LAP_STANDBY; - - timer_setup(&lap->idle_timer, NULL, 0); - - /* - * Insert into queue of LMP links - */ - hashbin_insert(irlmp->links, (irda_queue_t *) lap, lap->saddr, NULL); - - /* - * We set only this variable so IrLAP can tell us on which link the - * different events happened on - */ - irda_notify_init(notify); - notify->instance = lap; -} - -/* - * Function irlmp_unregister_irlap (saddr) - * - * IrLAP layer has been removed! - * - */ -void irlmp_unregister_link(__u32 saddr) -{ - struct lap_cb *link; - - /* We must remove ourselves from the hashbin *first*. This ensure - * that no more LSAPs will be open on this link and no discovery - * will be triggered anymore. Jean II */ - link = hashbin_remove(irlmp->links, saddr, NULL); - if (link) { - IRDA_ASSERT(link->magic == LMP_LAP_MAGIC, return;); - - /* Kill all the LSAPs on this link. Jean II */ - link->reason = LAP_DISC_INDICATION; - link->daddr = DEV_ADDR_ANY; - irlmp_do_lap_event(link, LM_LAP_DISCONNECT_INDICATION, NULL); - - /* Remove all discoveries discovered at this link */ - irlmp_expire_discoveries(irlmp->cachelog, link->saddr, TRUE); - - /* Final cleanup */ - del_timer(&link->idle_timer); - link->magic = 0; - hashbin_delete(link->lsaps, (FREE_FUNC) __irlmp_close_lsap); - kfree(link); - } -} - -/* - * Function irlmp_connect_request (handle, dlsap, userdata) - * - * Connect with a peer LSAP - * - */ -int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, - __u32 saddr, __u32 daddr, - struct qos_info *qos, struct sk_buff *userdata) -{ - struct sk_buff *tx_skb = userdata; - struct lap_cb *lap; - struct lsap_cb *lsap; - int ret; - - IRDA_ASSERT(self != NULL, return -EBADR;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;); - - pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", - __func__, self->slsap_sel, dlsap_sel, saddr, daddr); - - if (test_bit(0, &self->connected)) { - ret = -EISCONN; - goto err; - } - - /* Client must supply destination device address */ - if (!daddr) { - ret = -EINVAL; - goto err; - } - - /* Any userdata? */ - if (tx_skb == NULL) { - tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); - if (!tx_skb) - return -ENOMEM; - - skb_reserve(tx_skb, LMP_MAX_HEADER); - } - - /* Make room for MUX control header (3 bytes) */ - IRDA_ASSERT(skb_headroom(tx_skb) >= LMP_CONTROL_HEADER, return -1;); - skb_push(tx_skb, LMP_CONTROL_HEADER); - - self->dlsap_sel = dlsap_sel; - - /* - * Find the link to where we should try to connect since there may - * be more than one IrDA port on this machine. If the client has - * passed us the saddr (and already knows which link to use), then - * we use that to find the link, if not then we have to look in the - * discovery log and check if any of the links has discovered a - * device with the given daddr - */ - if ((!saddr) || (saddr == DEV_ADDR_ANY)) { - discovery_t *discovery; - unsigned long flags; - - spin_lock_irqsave(&irlmp->cachelog->hb_spinlock, flags); - if (daddr != DEV_ADDR_ANY) - discovery = hashbin_find(irlmp->cachelog, daddr, NULL); - else { - pr_debug("%s(), no daddr\n", __func__); - discovery = (discovery_t *) - hashbin_get_first(irlmp->cachelog); - } - - if (discovery) { - saddr = discovery->data.saddr; - daddr = discovery->data.daddr; - } - spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags); - } - lap = hashbin_lock_find(irlmp->links, saddr, NULL); - if (lap == NULL) { - pr_debug("%s(), Unable to find a usable link!\n", __func__); - ret = -EHOSTUNREACH; - goto err; - } - - /* Check if LAP is disconnected or already connected */ - if (lap->daddr == DEV_ADDR_ANY) - lap->daddr = daddr; - else if (lap->daddr != daddr) { - /* Check if some LSAPs are active on this LAP */ - if (HASHBIN_GET_SIZE(lap->lsaps) == 0) { - /* No active connection, but LAP hasn't been - * disconnected yet (waiting for timeout in LAP). - * Maybe we could give LAP a bit of help in this case. - */ - pr_debug("%s(), sorry, but I'm waiting for LAP to timeout!\n", - __func__); - ret = -EAGAIN; - goto err; - } - - /* LAP is already connected to a different node, and LAP - * can only talk to one node at a time */ - pr_debug("%s(), sorry, but link is busy!\n", __func__); - ret = -EBUSY; - goto err; - } - - self->lap = lap; - - /* - * Remove LSAP from list of unconnected LSAPs and insert it into the - * list of connected LSAPs for the particular link - */ - lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL); - - IRDA_ASSERT(lsap != NULL, return -1;); - IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_ASSERT(lsap->lap != NULL, return -1;); - IRDA_ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;); - - hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self, - NULL); - - set_bit(0, &self->connected); /* TRUE */ - - /* - * User supplied qos specifications? - */ - if (qos) - self->qos = *qos; - - irlmp_do_lsap_event(self, LM_CONNECT_REQUEST, tx_skb); - - /* Drop reference count - see irlap_data_request(). */ - dev_kfree_skb(tx_skb); - - return 0; - -err: - /* Cleanup */ - if(tx_skb) - dev_kfree_skb(tx_skb); - return ret; -} -EXPORT_SYMBOL(irlmp_connect_request); - -/* - * Function irlmp_connect_indication (self) - * - * Incoming connection - * - */ -void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) -{ - int max_seg_size; - int lap_header_size; - int max_header_size; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(self->lap != NULL, return;); - - pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", - __func__, self->slsap_sel, self->dlsap_sel); - - /* Note : self->lap is set in irlmp_link_data_indication(), - * (case CONNECT_CMD:) because we have no way to set it here. - * Similarly, self->dlsap_sel is usually set in irlmp_find_lsap(). - * Jean II */ - - self->qos = *self->lap->qos; - - max_seg_size = self->lap->qos->data_size.value-LMP_HEADER; - lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap); - max_header_size = LMP_HEADER + lap_header_size; - - /* Hide LMP_CONTROL_HEADER header from layer above */ - skb_pull(skb, LMP_CONTROL_HEADER); - - if (self->notify.connect_indication) { - /* Don't forget to refcount it - see irlap_driver_rcv(). */ - skb_get(skb); - self->notify.connect_indication(self->notify.instance, self, - &self->qos, max_seg_size, - max_header_size, skb); - } -} - -/* - * Function irlmp_connect_response (handle, userdata) - * - * Service user is accepting connection - * - */ -int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_ASSERT(userdata != NULL, return -1;); - - /* We set the connected bit and move the lsap to the connected list - * in the state machine itself. Jean II */ - - pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", - __func__, self->slsap_sel, self->dlsap_sel); - - /* Make room for MUX control header (3 bytes) */ - IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;); - skb_push(userdata, LMP_CONTROL_HEADER); - - irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata); - - /* Drop reference count - see irlap_data_request(). */ - dev_kfree_skb(userdata); - - return 0; -} -EXPORT_SYMBOL(irlmp_connect_response); - -/* - * Function irlmp_connect_confirm (handle, skb) - * - * LSAP connection confirmed peer device! - */ -void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) -{ - int max_header_size; - int lap_header_size; - int max_seg_size; - - IRDA_ASSERT(skb != NULL, return;); - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - IRDA_ASSERT(self->lap != NULL, return;); - - self->qos = *self->lap->qos; - - max_seg_size = self->lap->qos->data_size.value-LMP_HEADER; - lap_header_size = IRLAP_GET_HEADER_SIZE(self->lap->irlap); - max_header_size = LMP_HEADER + lap_header_size; - - pr_debug("%s(), max_header_size=%d\n", - __func__, max_header_size); - - /* Hide LMP_CONTROL_HEADER header from layer above */ - skb_pull(skb, LMP_CONTROL_HEADER); - - if (self->notify.connect_confirm) { - /* Don't forget to refcount it - see irlap_driver_rcv() */ - skb_get(skb); - self->notify.connect_confirm(self->notify.instance, self, - &self->qos, max_seg_size, - max_header_size, skb); - } -} - -/* - * Function irlmp_dup (orig, instance) - * - * Duplicate LSAP, can be used by servers to confirm a connection on a - * new LSAP so it can keep listening on the old one. - * - */ -struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) -{ - struct lsap_cb *new; - unsigned long flags; - - spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); - - /* Only allowed to duplicate unconnected LSAP's, and only LSAPs - * that have received a connect indication. Jean II */ - if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) || - (orig->lap == NULL)) { - pr_debug("%s(), invalid LSAP (wrong state)\n", - __func__); - spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, - flags); - return NULL; - } - - /* Allocate a new instance */ - new = kmemdup(orig, sizeof(*new), GFP_ATOMIC); - if (!new) { - pr_debug("%s(), unable to kmalloc\n", __func__); - spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, - flags); - return NULL; - } - /* new->lap = orig->lap; => done in the memcpy() */ - /* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */ - new->conn_skb = NULL; - - spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); - - /* Not everything is the same */ - new->notify.instance = instance; - - timer_setup(&new->watchdog_timer, NULL, 0); - - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, - (long) new, NULL); - -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - /* Make sure that we invalidate the LSAP cache */ - new->lap->cache.valid = FALSE; -#endif /* CONFIG_IRDA_CACHE_LAST_LSAP */ - - return new; -} - -/* - * Function irlmp_disconnect_request (handle, userdata) - * - * The service user is requesting disconnection, this will not remove the - * LSAP, but only mark it as disconnected - */ -int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) -{ - struct lsap_cb *lsap; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_ASSERT(userdata != NULL, return -1;); - - /* Already disconnected ? - * There is a race condition between irlmp_disconnect_indication() - * and us that might mess up the hashbins below. This fixes it. - * Jean II */ - if (! test_and_clear_bit(0, &self->connected)) { - pr_debug("%s(), already disconnected!\n", __func__); - dev_kfree_skb(userdata); - return -1; - } - - skb_push(userdata, LMP_CONTROL_HEADER); - - /* - * Do the event before the other stuff since we must know - * which lap layer that the frame should be transmitted on - */ - irlmp_do_lsap_event(self, LM_DISCONNECT_REQUEST, userdata); - - /* Drop reference count - see irlap_data_request(). */ - dev_kfree_skb(userdata); - - /* - * Remove LSAP from list of connected LSAPs for the particular link - * and insert it into the list of unconnected LSAPs - */ - IRDA_ASSERT(self->lap != NULL, return -1;); - IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); - IRDA_ASSERT(self->lap->lsaps != NULL, return -1;); - - lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - self->lap->cache.valid = FALSE; -#endif - - IRDA_ASSERT(lsap != NULL, return -1;); - IRDA_ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_ASSERT(lsap == self, return -1;); - - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, - (long) self, NULL); - - /* Reset some values */ - self->dlsap_sel = LSAP_ANY; - self->lap = NULL; - - return 0; -} -EXPORT_SYMBOL(irlmp_disconnect_request); - -/* - * Function irlmp_disconnect_indication (reason, userdata) - * - * LSAP is being closed! - */ -void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, - struct sk_buff *skb) -{ - struct lsap_cb *lsap; - - pr_debug("%s(), reason=%s [%d]\n", __func__, - irlmp_reason_str(reason), reason); - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - - pr_debug("%s(), slsap_sel=%02x, dlsap_sel=%02x\n", - __func__, self->slsap_sel, self->dlsap_sel); - - /* Already disconnected ? - * There is a race condition between irlmp_disconnect_request() - * and us that might mess up the hashbins below. This fixes it. - * Jean II */ - if (! test_and_clear_bit(0, &self->connected)) { - pr_debug("%s(), already disconnected!\n", __func__); - return; - } - - /* - * Remove association between this LSAP and the link it used - */ - IRDA_ASSERT(self->lap != NULL, return;); - IRDA_ASSERT(self->lap->lsaps != NULL, return;); - - lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL); -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - self->lap->cache.valid = FALSE; -#endif - - IRDA_ASSERT(lsap != NULL, return;); - IRDA_ASSERT(lsap == self, return;); - hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, - (long) lsap, NULL); - - self->dlsap_sel = LSAP_ANY; - self->lap = NULL; - - /* - * Inform service user - */ - if (self->notify.disconnect_indication) { - /* Don't forget to refcount it - see irlap_driver_rcv(). */ - if(skb) - skb_get(skb); - self->notify.disconnect_indication(self->notify.instance, - self, reason, skb); - } else { - pr_debug("%s(), no handler\n", __func__); - } -} - -/* - * Function irlmp_do_expiry (void) - * - * Do a cleanup of the discovery log (remove old entries) - * - * Note : separate from irlmp_do_discovery() so that we can handle - * passive discovery properly. - */ -void irlmp_do_expiry(void) -{ - struct lap_cb *lap; - - /* - * Expire discovery on all links which are *not* connected. - * On links which are connected, we can't do discovery - * anymore and can't refresh the log, so we freeze the - * discovery log to keep info about the device we are - * connected to. - * This info is mandatory if we want irlmp_connect_request() - * to work properly. - Jean II - */ - lap = (struct lap_cb *) hashbin_get_first(irlmp->links); - while (lap != NULL) { - IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); - - if (lap->lap_state == LAP_STANDBY) { - /* Expire discoveries discovered on this link */ - irlmp_expire_discoveries(irlmp->cachelog, lap->saddr, - FALSE); - } - lap = (struct lap_cb *) hashbin_get_next(irlmp->links); - } -} - -/* - * Function irlmp_do_discovery (nslots) - * - * Do some discovery on all links - * - * Note : log expiry is done above. - */ -void irlmp_do_discovery(int nslots) -{ - struct lap_cb *lap; - __u16 *data_hintsp; - - /* Make sure the value is sane */ - if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){ - net_warn_ratelimited("%s: invalid value for number of slots!\n", - __func__); - nslots = sysctl_discovery_slots = 8; - } - - /* Construct new discovery info to be used by IrLAP, */ - data_hintsp = (__u16 *) irlmp->discovery_cmd.data.hints; - put_unaligned(irlmp->hints.word, data_hintsp); - - /* - * Set character set for device name (we use ASCII), and - * copy device name. Remember to make room for a \0 at the - * end - */ - irlmp->discovery_cmd.data.charset = CS_ASCII; - strncpy(irlmp->discovery_cmd.data.info, sysctl_devname, - NICKNAME_MAX_LEN); - irlmp->discovery_cmd.name_len = strlen(irlmp->discovery_cmd.data.info); - irlmp->discovery_cmd.nslots = nslots; - - /* - * Try to send discovery packets on all links - */ - lap = (struct lap_cb *) hashbin_get_first(irlmp->links); - while (lap != NULL) { - IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); - - if (lap->lap_state == LAP_STANDBY) { - /* Try to discover */ - irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST, - NULL); - } - lap = (struct lap_cb *) hashbin_get_next(irlmp->links); - } -} - -/* - * Function irlmp_discovery_request (nslots) - * - * Do a discovery of devices in front of the computer - * - * If the caller has registered a client discovery callback, this - * allow him to receive the full content of the discovery log through - * this callback (as normally he will receive only new discoveries). - */ -void irlmp_discovery_request(int nslots) -{ - /* Return current cached discovery log (in full) */ - irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_LOG); - - /* - * Start a single discovery operation if discovery is not already - * running - */ - if (!sysctl_discovery) { - /* Check if user wants to override the default */ - if (nslots == DISCOVERY_DEFAULT_SLOTS) - nslots = sysctl_discovery_slots; - - irlmp_do_discovery(nslots); - /* Note : we never do expiry here. Expiry will run on the - * discovery timer regardless of the state of sysctl_discovery - * Jean II */ - } -} -EXPORT_SYMBOL(irlmp_discovery_request); - -/* - * Function irlmp_get_discoveries (pn, mask, slots) - * - * Return the current discovery log - * - * If discovery is not enabled, you should call this function again - * after 1 or 2 seconds (i.e. after discovery has been done). - */ -struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots) -{ - /* If discovery is not enabled, it's likely that the discovery log - * will be empty. So, we trigger a single discovery, so that next - * time the user call us there might be some results in the log. - * Jean II - */ - if (!sysctl_discovery) { - /* Check if user wants to override the default */ - if (nslots == DISCOVERY_DEFAULT_SLOTS) - nslots = sysctl_discovery_slots; - - /* Start discovery - will complete sometime later */ - irlmp_do_discovery(nslots); - /* Note : we never do expiry here. Expiry will run on the - * discovery timer regardless of the state of sysctl_discovery - * Jean II */ - } - - /* Return current cached discovery log */ - return irlmp_copy_discoveries(irlmp->cachelog, pn, mask, TRUE); -} -EXPORT_SYMBOL(irlmp_get_discoveries); - -/* - * Function irlmp_notify_client (log) - * - * Notify all about discovered devices - * - * Clients registered with IrLMP are : - * o IrComm - * o IrLAN - * o Any socket (in any state - ouch, that may be a lot !) - * The client may have defined a callback to be notified in case of - * partial/selective discovery based on the hints that it passed to IrLMP. - */ -static inline void -irlmp_notify_client(irlmp_client_t *client, - hashbin_t *log, DISCOVERY_MODE mode) -{ - discinfo_t *discoveries; /* Copy of the discovery log */ - int number; /* Number of nodes in the log */ - int i; - - /* Check if client wants or not partial/selective log (optimisation) */ - if (!client->disco_callback) - return; - - /* - * Locking notes : - * the old code was manipulating the log directly, which was - * very racy. Now, we use copy_discoveries, that protects - * itself while dumping the log for us. - * The overhead of the copy is compensated by the fact that - * we only pass new discoveries in normal mode and don't - * pass the same old entry every 3s to the caller as we used - * to do (virtual function calling is expensive). - * Jean II - */ - - /* - * Now, check all discovered devices (if any), and notify client - * only about the services that the client is interested in - * We also notify only about the new devices unless the caller - * explicitly request a dump of the log. Jean II - */ - discoveries = irlmp_copy_discoveries(log, &number, - client->hint_mask.word, - (mode == DISCOVERY_LOG)); - /* Check if the we got some results */ - if (discoveries == NULL) - return; /* No nodes discovered */ - - /* Pass all entries to the listener */ - for(i = 0; i < number; i++) - client->disco_callback(&(discoveries[i]), mode, client->priv); - - /* Free up our buffer */ - kfree(discoveries); -} - -/* - * Function irlmp_discovery_confirm ( self, log) - * - * Some device(s) answered to our discovery request! Check to see which - * device it is, and give indication to the client(s) - * - */ -void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode) -{ - irlmp_client_t *client; - irlmp_client_t *client_next; - - IRDA_ASSERT(log != NULL, return;); - - if (!(HASHBIN_GET_SIZE(log))) - return; - - /* For each client - notify callback may touch client list */ - client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); - while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, - (void *) &client_next) ) { - /* Check if we should notify client */ - irlmp_notify_client(client, log, mode); - - client = client_next; - } -} - -/* - * Function irlmp_discovery_expiry (expiry) - * - * This device is no longer been discovered, and therefore it is being - * purged from the discovery log. Inform all clients who have - * registered for this event... - * - * Note : called exclusively from discovery.c - * Note : this is no longer called under discovery spinlock, so the - * client can do whatever he wants in the callback. - */ -void irlmp_discovery_expiry(discinfo_t *expiries, int number) -{ - irlmp_client_t *client; - irlmp_client_t *client_next; - int i; - - IRDA_ASSERT(expiries != NULL, return;); - - /* For each client - notify callback may touch client list */ - client = (irlmp_client_t *) hashbin_get_first(irlmp->clients); - while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL, - (void *) &client_next) ) { - - /* Pass all entries to the listener */ - for(i = 0; i < number; i++) { - /* Check if we should notify client */ - if ((client->expir_callback) && - (client->hint_mask.word & - get_unaligned((__u16 *)expiries[i].hints) - & 0x7f7f) ) - client->expir_callback(&(expiries[i]), - EXPIRY_TIMEOUT, - client->priv); - } - - /* Next client */ - client = client_next; - } -} - -/* - * Function irlmp_get_discovery_response () - * - * Used by IrLAP to get the discovery info it needs when answering - * discovery requests by other devices. - */ -discovery_t *irlmp_get_discovery_response(void) -{ - IRDA_ASSERT(irlmp != NULL, return NULL;); - - put_unaligned(irlmp->hints.word, (__u16 *)irlmp->discovery_rsp.data.hints); - - /* - * Set character set for device name (we use ASCII), and - * copy device name. Remember to make room for a \0 at the - * end - */ - irlmp->discovery_rsp.data.charset = CS_ASCII; - - strncpy(irlmp->discovery_rsp.data.info, sysctl_devname, - NICKNAME_MAX_LEN); - irlmp->discovery_rsp.name_len = strlen(irlmp->discovery_rsp.data.info); - - return &irlmp->discovery_rsp; -} - -/* - * Function irlmp_data_request (self, skb) - * - * Send some data to peer device - * - * Note on skb management : - * After calling the lower layers of the IrDA stack, we always - * kfree() the skb, which drop the reference count (and potentially - * destroy it). - * IrLMP and IrLAP may queue the packet, and in those cases will need - * to use skb_get() to keep it around. - * Jean II - */ -int irlmp_data_request(struct lsap_cb *self, struct sk_buff *userdata) -{ - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - - /* Make room for MUX header */ - IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); - skb_push(userdata, LMP_HEADER); - - ret = irlmp_do_lsap_event(self, LM_DATA_REQUEST, userdata); - - /* Drop reference count - see irlap_data_request(). */ - dev_kfree_skb(userdata); - - return ret; -} -EXPORT_SYMBOL(irlmp_data_request); - -/* - * Function irlmp_data_indication (handle, skb) - * - * Got data from LAP layer so pass it up to upper layer - * - */ -void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) -{ - /* Hide LMP header from layer above */ - skb_pull(skb, LMP_HEADER); - - if (self->notify.data_indication) { - /* Don't forget to refcount it - see irlap_driver_rcv(). */ - skb_get(skb); - self->notify.data_indication(self->notify.instance, self, skb); - } -} - -/* - * Function irlmp_udata_request (self, skb) - */ -int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata) -{ - int ret; - - IRDA_ASSERT(userdata != NULL, return -1;); - - /* Make room for MUX header */ - IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER, return -1;); - skb_push(userdata, LMP_HEADER); - - ret = irlmp_do_lsap_event(self, LM_UDATA_REQUEST, userdata); - - /* Drop reference count - see irlap_data_request(). */ - dev_kfree_skb(userdata); - - return ret; -} - -/* - * Function irlmp_udata_indication (self, skb) - * - * Send unreliable data (but still within the connection) - * - */ -void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - /* Hide LMP header from layer above */ - skb_pull(skb, LMP_HEADER); - - if (self->notify.udata_indication) { - /* Don't forget to refcount it - see irlap_driver_rcv(). */ - skb_get(skb); - self->notify.udata_indication(self->notify.instance, self, - skb); - } -} - -/* - * Function irlmp_connless_data_request (self, skb) - */ -#ifdef CONFIG_IRDA_ULTRA -int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata, - __u8 pid) -{ - struct sk_buff *clone_skb; - struct lap_cb *lap; - - IRDA_ASSERT(userdata != NULL, return -1;); - - /* Make room for MUX and PID header */ - IRDA_ASSERT(skb_headroom(userdata) >= LMP_HEADER+LMP_PID_HEADER, - return -1;); - - /* Insert protocol identifier */ - skb_push(userdata, LMP_PID_HEADER); - if(self != NULL) - userdata->data[0] = self->pid; - else - userdata->data[0] = pid; - - /* Connectionless sockets must use 0x70 */ - skb_push(userdata, LMP_HEADER); - userdata->data[0] = userdata->data[1] = LSAP_CONNLESS; - - /* Try to send Connectionless packets out on all links */ - lap = (struct lap_cb *) hashbin_get_first(irlmp->links); - while (lap != NULL) { - IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return -1;); - - clone_skb = skb_clone(userdata, GFP_ATOMIC); - if (!clone_skb) { - dev_kfree_skb(userdata); - return -ENOMEM; - } - - irlap_unitdata_request(lap->irlap, clone_skb); - /* irlap_unitdata_request() don't increase refcount, - * so no dev_kfree_skb() - Jean II */ - - lap = (struct lap_cb *) hashbin_get_next(irlmp->links); - } - dev_kfree_skb(userdata); - - return 0; -} -#endif /* CONFIG_IRDA_ULTRA */ - -/* - * Function irlmp_connless_data_indication (self, skb) - * - * Receive unreliable data outside any connection. Mostly used by Ultra - * - */ -#ifdef CONFIG_IRDA_ULTRA -void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - /* Hide LMP and PID header from layer above */ - skb_pull(skb, LMP_HEADER+LMP_PID_HEADER); - - if (self->notify.udata_indication) { - /* Don't forget to refcount it - see irlap_driver_rcv(). */ - skb_get(skb); - self->notify.udata_indication(self->notify.instance, self, - skb); - } -} -#endif /* CONFIG_IRDA_ULTRA */ - -/* - * Propagate status indication from LAP to LSAPs (via LMP) - * This don't trigger any change of state in lap_cb, lmp_cb or lsap_cb, - * and the event is stateless, therefore we can bypass both state machines - * and send the event direct to the LSAP user. - * Jean II - */ -void irlmp_status_indication(struct lap_cb *self, - LINK_STATUS link, LOCK_STATUS lock) -{ - struct lsap_cb *next; - struct lsap_cb *curr; - - /* Send status_indication to all LSAPs using this link */ - curr = (struct lsap_cb *) hashbin_get_first( self->lsaps); - while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL, - (void *) &next) ) { - IRDA_ASSERT(curr->magic == LMP_LSAP_MAGIC, return;); - /* - * Inform service user if he has requested it - */ - if (curr->notify.status_indication != NULL) - curr->notify.status_indication(curr->notify.instance, - link, lock); - else - pr_debug("%s(), no handler\n", __func__); - - curr = next; - } -} - -/* - * Receive flow control indication from LAP. - * LAP want us to send it one more frame. We implement a simple round - * robin scheduler between the active sockets so that we get a bit of - * fairness. Note that the round robin is far from perfect, but it's - * better than nothing. - * We then poll the selected socket so that we can do synchronous - * refilling of IrLAP (which allow to minimise the number of buffers). - * Jean II - */ -void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow) -{ - struct lsap_cb *next; - struct lsap_cb *curr; - int lsap_todo; - - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - IRDA_ASSERT(flow == FLOW_START, return;); - - /* Get the number of lsap. That's the only safe way to know - * that we have looped around... - Jean II */ - lsap_todo = HASHBIN_GET_SIZE(self->lsaps); - pr_debug("%s() : %d lsaps to scan\n", __func__, lsap_todo); - - /* Poll lsap in order until the queue is full or until we - * tried them all. - * Most often, the current LSAP will have something to send, - * so we will go through this loop only once. - Jean II */ - while((lsap_todo--) && - (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) { - /* Try to find the next lsap we should poll. */ - next = self->flow_next; - /* If we have no lsap, restart from first one */ - if(next == NULL) - next = (struct lsap_cb *) hashbin_get_first(self->lsaps); - /* Verify current one and find the next one */ - curr = hashbin_find_next(self->lsaps, (long) next, NULL, - (void *) &self->flow_next); - /* Uh-oh... Paranoia */ - if(curr == NULL) - break; - pr_debug("%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", - __func__, curr, next, self->flow_next, lsap_todo, - IRLAP_GET_TX_QUEUE_LEN(self->irlap)); - - /* Inform lsap user that it can send one more packet. */ - if (curr->notify.flow_indication != NULL) - curr->notify.flow_indication(curr->notify.instance, - curr, flow); - else - pr_debug("%s(), no handler\n", __func__); - } -} - -#if 0 -/* - * Function irlmp_hint_to_service (hint) - * - * Returns a list of all servics contained in the given hint bits. This - * function assumes that the hint bits have the size of two bytes only - */ -__u8 *irlmp_hint_to_service(__u8 *hint) -{ - __u8 *service; - int i = 0; - - /* - * Allocate array to store services in. 16 entries should be safe - * since we currently only support 2 hint bytes - */ - service = kmalloc(16, GFP_ATOMIC); - if (!service) - return NULL; - - if (!hint[0]) { - pr_debug("<None>\n"); - kfree(service); - return NULL; - } - if (hint[0] & HINT_PNP) - pr_debug("PnP Compatible "); - if (hint[0] & HINT_PDA) - pr_debug("PDA/Palmtop "); - if (hint[0] & HINT_COMPUTER) - pr_debug("Computer "); - if (hint[0] & HINT_PRINTER) { - pr_debug("Printer "); - service[i++] = S_PRINTER; - } - if (hint[0] & HINT_MODEM) - pr_debug("Modem "); - if (hint[0] & HINT_FAX) - pr_debug("Fax "); - if (hint[0] & HINT_LAN) { - pr_debug("LAN Access "); - service[i++] = S_LAN; - } - /* - * Test if extension byte exists. This byte will usually be - * there, but this is not really required by the standard. - * (IrLMP p. 29) - */ - if (hint[0] & HINT_EXTENSION) { - if (hint[1] & HINT_TELEPHONY) { - pr_debug("Telephony "); - service[i++] = S_TELEPHONY; - } - if (hint[1] & HINT_FILE_SERVER) - pr_debug("File Server "); - - if (hint[1] & HINT_COMM) { - pr_debug("IrCOMM "); - service[i++] = S_COMM; - } - if (hint[1] & HINT_OBEX) { - pr_debug("IrOBEX "); - service[i++] = S_OBEX; - } - } - pr_debug("\n"); - - /* So that client can be notified about any discovery */ - service[i++] = S_ANY; - - service[i] = S_END; - - return service; -} -#endif - -static const __u16 service_hint_mapping[S_END][2] = { - { HINT_PNP, 0 }, /* S_PNP */ - { HINT_PDA, 0 }, /* S_PDA */ - { HINT_COMPUTER, 0 }, /* S_COMPUTER */ - { HINT_PRINTER, 0 }, /* S_PRINTER */ - { HINT_MODEM, 0 }, /* S_MODEM */ - { HINT_FAX, 0 }, /* S_FAX */ - { HINT_LAN, 0 }, /* S_LAN */ - { HINT_EXTENSION, HINT_TELEPHONY }, /* S_TELEPHONY */ - { HINT_EXTENSION, HINT_COMM }, /* S_COMM */ - { HINT_EXTENSION, HINT_OBEX }, /* S_OBEX */ - { 0xFF, 0xFF }, /* S_ANY */ -}; - -/* - * Function irlmp_service_to_hint (service) - * - * Converts a service type, to a hint bit - * - * Returns: a 16 bit hint value, with the service bit set - */ -__u16 irlmp_service_to_hint(int service) -{ - __u16_host_order hint; - - hint.byte[0] = service_hint_mapping[service][0]; - hint.byte[1] = service_hint_mapping[service][1]; - - return hint.word; -} -EXPORT_SYMBOL(irlmp_service_to_hint); - -/* - * Function irlmp_register_service (service) - * - * Register local service with IrLMP - * - */ -void *irlmp_register_service(__u16 hints) -{ - irlmp_service_t *service; - - pr_debug("%s(), hints = %04x\n", __func__, hints); - - /* Make a new registration */ - service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); - if (!service) - return NULL; - - service->hints.word = hints; - hashbin_insert(irlmp->services, (irda_queue_t *) service, - (long) service, NULL); - - irlmp->hints.word |= hints; - - return (void *)service; -} -EXPORT_SYMBOL(irlmp_register_service); - -/* - * Function irlmp_unregister_service (handle) - * - * Unregister service with IrLMP. - * - * Returns: 0 on success, -1 on error - */ -int irlmp_unregister_service(void *handle) -{ - irlmp_service_t *service; - unsigned long flags; - - if (!handle) - return -1; - - /* Caller may call with invalid handle (it's legal) - Jean II */ - service = hashbin_lock_find(irlmp->services, (long) handle, NULL); - if (!service) { - pr_debug("%s(), Unknown service!\n", __func__); - return -1; - } - - hashbin_remove_this(irlmp->services, (irda_queue_t *) service); - kfree(service); - - /* Remove old hint bits */ - irlmp->hints.word = 0; - - /* Refresh current hint bits */ - spin_lock_irqsave(&irlmp->services->hb_spinlock, flags); - service = (irlmp_service_t *) hashbin_get_first(irlmp->services); - while (service) { - irlmp->hints.word |= service->hints.word; - - service = (irlmp_service_t *)hashbin_get_next(irlmp->services); - } - spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags); - return 0; -} -EXPORT_SYMBOL(irlmp_unregister_service); - -/* - * Function irlmp_register_client (hint_mask, callback1, callback2) - * - * Register a local client with IrLMP - * First callback is selective discovery (based on hints) - * Second callback is for selective discovery expiries - * - * Returns: handle > 0 on success, 0 on error - */ -void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, - DISCOVERY_CALLBACK2 expir_clb, void *priv) -{ - irlmp_client_t *client; - - IRDA_ASSERT(irlmp != NULL, return NULL;); - - /* Make a new registration */ - client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC); - if (!client) - return NULL; - - /* Register the details */ - client->hint_mask.word = hint_mask; - client->disco_callback = disco_clb; - client->expir_callback = expir_clb; - client->priv = priv; - - hashbin_insert(irlmp->clients, (irda_queue_t *) client, - (long) client, NULL); - - return (void *) client; -} -EXPORT_SYMBOL(irlmp_register_client); - -/* - * Function irlmp_update_client (handle, hint_mask, callback1, callback2) - * - * Updates specified client (handle) with possibly new hint_mask and - * callback - * - * Returns: 0 on success, -1 on error - */ -int irlmp_update_client(void *handle, __u16 hint_mask, - DISCOVERY_CALLBACK1 disco_clb, - DISCOVERY_CALLBACK2 expir_clb, void *priv) -{ - irlmp_client_t *client; - - if (!handle) - return -1; - - client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); - if (!client) { - pr_debug("%s(), Unknown client!\n", __func__); - return -1; - } - - client->hint_mask.word = hint_mask; - client->disco_callback = disco_clb; - client->expir_callback = expir_clb; - client->priv = priv; - - return 0; -} -EXPORT_SYMBOL(irlmp_update_client); - -/* - * Function irlmp_unregister_client (handle) - * - * Returns: 0 on success, -1 on error - * - */ -int irlmp_unregister_client(void *handle) -{ - struct irlmp_client *client; - - if (!handle) - return -1; - - /* Caller may call with invalid handle (it's legal) - Jean II */ - client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); - if (!client) { - pr_debug("%s(), Unknown client!\n", __func__); - return -1; - } - - pr_debug("%s(), removing client!\n", __func__); - hashbin_remove_this(irlmp->clients, (irda_queue_t *) client); - kfree(client); - - return 0; -} -EXPORT_SYMBOL(irlmp_unregister_client); - -/* - * Function irlmp_slsap_inuse (slsap) - * - * Check if the given source LSAP selector is in use - * - * This function is clearly not very efficient. On the mitigating side, the - * stack make sure that in 99% of the cases, we are called only once - * for each socket allocation. We could probably keep a bitmap - * of the allocated LSAP, but I'm not sure the complexity is worth it. - * Jean II - */ -static int irlmp_slsap_inuse(__u8 slsap_sel) -{ - struct lsap_cb *self; - struct lap_cb *lap; - unsigned long flags; - - IRDA_ASSERT(irlmp != NULL, return TRUE;); - IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;); - IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;); - -#ifdef CONFIG_IRDA_ULTRA - /* Accept all bindings to the connectionless LSAP */ - if (slsap_sel == LSAP_CONNLESS) - return FALSE; -#endif /* CONFIG_IRDA_ULTRA */ - - /* Valid values are between 0 and 127 (0x0-0x6F) */ - if (slsap_sel > LSAP_MAX) - return TRUE; - - /* - * Check if slsap is already in use. To do this we have to loop over - * every IrLAP connection and check every LSAP associated with each - * the connection. - */ - spin_lock_irqsave_nested(&irlmp->links->hb_spinlock, flags, - SINGLE_DEPTH_NESTING); - lap = (struct lap_cb *) hashbin_get_first(irlmp->links); - while (lap != NULL) { - IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, goto errlap;); - - /* Careful for priority inversions here ! - * irlmp->links is never taken while another IrDA - * spinlock is held, so we are safe. Jean II */ - spin_lock(&lap->lsaps->hb_spinlock); - - /* For this IrLAP, check all the LSAPs */ - self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); - while (self != NULL) { - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, - goto errlsap;); - - if (self->slsap_sel == slsap_sel) { - pr_debug("Source LSAP selector=%02x in use\n", - self->slsap_sel); - goto errlsap; - } - self = (struct lsap_cb*) hashbin_get_next(lap->lsaps); - } - spin_unlock(&lap->lsaps->hb_spinlock); - - /* Next LAP */ - lap = (struct lap_cb *) hashbin_get_next(irlmp->links); - } - spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); - - /* - * Server sockets are typically waiting for connections and - * therefore reside in the unconnected list. We don't want - * to give out their LSAPs for obvious reasons... - * Jean II - */ - spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); - - self = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); - while (self != NULL) { - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, goto erruncon;); - if (self->slsap_sel == slsap_sel) { - pr_debug("Source LSAP selector=%02x in use (unconnected)\n", - self->slsap_sel); - goto erruncon; - } - self = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps); - } - spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); - - return FALSE; - - /* Error exit from within one of the two nested loops. - * Make sure we release the right spinlock in the righ order. - * Jean II */ -errlsap: - spin_unlock(&lap->lsaps->hb_spinlock); -IRDA_ASSERT_LABEL(errlap:) - spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags); - return TRUE; - - /* Error exit from within the unconnected loop. - * Just one spinlock to release... Jean II */ -erruncon: - spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); - return TRUE; -} - -/* - * Function irlmp_find_free_slsap () - * - * Find a free source LSAP to use. This function is called if the service - * user has requested a source LSAP equal to LM_ANY - */ -static __u8 irlmp_find_free_slsap(void) -{ - __u8 lsap_sel; - int wrapped = 0; - - IRDA_ASSERT(irlmp != NULL, return -1;); - IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return -1;); - - /* Most users don't really care which LSAPs they are given, - * and therefore we automatically give them a free LSAP. - * This function try to find a suitable LSAP, i.e. which is - * not in use and is within the acceptable range. Jean II */ - - do { - /* Always increment to LSAP number before using it. - * In theory, we could reuse the last LSAP number, as long - * as it is no longer in use. Some IrDA stack do that. - * However, the previous socket may be half closed, i.e. - * we closed it, we think it's no longer in use, but the - * other side did not receive our close and think it's - * active and still send data on it. - * This is similar to what is done with PIDs and TCP ports. - * Also, this reduce the number of calls to irlmp_slsap_inuse() - * which is an expensive function to call. - * Jean II */ - irlmp->last_lsap_sel++; - - /* Check if we need to wraparound (0x70-0x7f are reserved) */ - if (irlmp->last_lsap_sel > LSAP_MAX) { - /* 0x00-0x10 are also reserved for well know ports */ - irlmp->last_lsap_sel = 0x10; - - /* Make sure we terminate the loop */ - if (wrapped++) { - net_err_ratelimited("%s: no more free LSAPs !\n", - __func__); - return 0; - } - } - - /* If the LSAP is in use, try the next one. - * Despite the autoincrement, we need to check if the lsap - * is really in use or not, first because LSAP may be - * directly allocated in irlmp_open_lsap(), and also because - * we may wraparound on old sockets. Jean II */ - } while (irlmp_slsap_inuse(irlmp->last_lsap_sel)); - - /* Got it ! */ - lsap_sel = irlmp->last_lsap_sel; - pr_debug("%s(), found free lsap_sel=%02x\n", - __func__, lsap_sel); - - return lsap_sel; -} - -/* - * Function irlmp_convert_lap_reason (lap_reason) - * - * Converts IrLAP disconnect reason codes to IrLMP disconnect reason - * codes - * - */ -LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason) -{ - int reason = LM_LAP_DISCONNECT; - - switch (lap_reason) { - case LAP_DISC_INDICATION: /* Received a disconnect request from peer */ - pr_debug("%s(), LAP_DISC_INDICATION\n", __func__); - reason = LM_USER_REQUEST; - break; - case LAP_NO_RESPONSE: /* To many retransmits without response */ - pr_debug("%s(), LAP_NO_RESPONSE\n", __func__); - reason = LM_LAP_DISCONNECT; - break; - case LAP_RESET_INDICATION: - pr_debug("%s(), LAP_RESET_INDICATION\n", __func__); - reason = LM_LAP_RESET; - break; - case LAP_FOUND_NONE: - case LAP_MEDIA_BUSY: - case LAP_PRIMARY_CONFLICT: - pr_debug("%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", - __func__); - reason = LM_CONNECT_FAILURE; - break; - default: - pr_debug("%s(), Unknown IrLAP disconnect reason %d!\n", - __func__, lap_reason); - reason = LM_LAP_DISCONNECT; - break; - } - - return reason; -} - -#ifdef CONFIG_PROC_FS - -struct irlmp_iter_state { - hashbin_t *hashbin; -}; - -#define LSAP_START_TOKEN ((void *)1) -#define LINK_START_TOKEN ((void *)2) - -static void *irlmp_seq_hb_idx(struct irlmp_iter_state *iter, loff_t *off) -{ - void *element; - - spin_lock_irq(&iter->hashbin->hb_spinlock); - for (element = hashbin_get_first(iter->hashbin); - element != NULL; - element = hashbin_get_next(iter->hashbin)) { - if (!off || (*off)-- == 0) { - /* NB: hashbin left locked */ - return element; - } - } - spin_unlock_irq(&iter->hashbin->hb_spinlock); - iter->hashbin = NULL; - return NULL; -} - - -static void *irlmp_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct irlmp_iter_state *iter = seq->private; - void *v; - loff_t off = *pos; - - iter->hashbin = NULL; - if (off-- == 0) - return LSAP_START_TOKEN; - - iter->hashbin = irlmp->unconnected_lsaps; - v = irlmp_seq_hb_idx(iter, &off); - if (v) - return v; - - if (off-- == 0) - return LINK_START_TOKEN; - - iter->hashbin = irlmp->links; - return irlmp_seq_hb_idx(iter, &off); -} - -static void *irlmp_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct irlmp_iter_state *iter = seq->private; - - ++*pos; - - if (v == LSAP_START_TOKEN) { /* start of list of lsaps */ - iter->hashbin = irlmp->unconnected_lsaps; - v = irlmp_seq_hb_idx(iter, NULL); - return v ? v : LINK_START_TOKEN; - } - - if (v == LINK_START_TOKEN) { /* start of list of links */ - iter->hashbin = irlmp->links; - return irlmp_seq_hb_idx(iter, NULL); - } - - v = hashbin_get_next(iter->hashbin); - - if (v == NULL) { /* no more in this hash bin */ - spin_unlock_irq(&iter->hashbin->hb_spinlock); - - if (iter->hashbin == irlmp->unconnected_lsaps) - v = LINK_START_TOKEN; - - iter->hashbin = NULL; - } - return v; -} - -static void irlmp_seq_stop(struct seq_file *seq, void *v) -{ - struct irlmp_iter_state *iter = seq->private; - - if (iter->hashbin) - spin_unlock_irq(&iter->hashbin->hb_spinlock); -} - -static int irlmp_seq_show(struct seq_file *seq, void *v) -{ - const struct irlmp_iter_state *iter = seq->private; - struct lsap_cb *self = v; - - if (v == LSAP_START_TOKEN) - seq_puts(seq, "Unconnected LSAPs:\n"); - else if (v == LINK_START_TOKEN) - seq_puts(seq, "\nRegistered Link Layers:\n"); - else if (iter->hashbin == irlmp->unconnected_lsaps) { - self = v; - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -EINVAL; ); - seq_printf(seq, "lsap state: %s, ", - irlsap_state[ self->lsap_state]); - seq_printf(seq, - "slsap_sel: %#02x, dlsap_sel: %#02x, ", - self->slsap_sel, self->dlsap_sel); - seq_printf(seq, "(%s)", self->notify.name); - seq_printf(seq, "\n"); - } else if (iter->hashbin == irlmp->links) { - struct lap_cb *lap = v; - - seq_printf(seq, "lap state: %s, ", - irlmp_state[lap->lap_state]); - - seq_printf(seq, "saddr: %#08x, daddr: %#08x, ", - lap->saddr, lap->daddr); - seq_printf(seq, "num lsaps: %d", - HASHBIN_GET_SIZE(lap->lsaps)); - seq_printf(seq, "\n"); - - /* Careful for priority inversions here ! - * All other uses of attrib spinlock are independent of - * the object spinlock, so we are safe. Jean II */ - spin_lock(&lap->lsaps->hb_spinlock); - - seq_printf(seq, "\n Connected LSAPs:\n"); - for (self = (struct lsap_cb *) hashbin_get_first(lap->lsaps); - self != NULL; - self = (struct lsap_cb *)hashbin_get_next(lap->lsaps)) { - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, - goto outloop;); - seq_printf(seq, " lsap state: %s, ", - irlsap_state[ self->lsap_state]); - seq_printf(seq, - "slsap_sel: %#02x, dlsap_sel: %#02x, ", - self->slsap_sel, self->dlsap_sel); - seq_printf(seq, "(%s)", self->notify.name); - seq_putc(seq, '\n'); - - } - IRDA_ASSERT_LABEL(outloop:) - spin_unlock(&lap->lsaps->hb_spinlock); - seq_putc(seq, '\n'); - } else - return -EINVAL; - - return 0; -} - -static const struct seq_operations irlmp_seq_ops = { - .start = irlmp_seq_start, - .next = irlmp_seq_next, - .stop = irlmp_seq_stop, - .show = irlmp_seq_show, -}; - -static int irlmp_seq_open(struct inode *inode, struct file *file) -{ - IRDA_ASSERT(irlmp != NULL, return -EINVAL;); - - return seq_open_private(file, &irlmp_seq_ops, - sizeof(struct irlmp_iter_state)); -} - -const struct file_operations irlmp_seq_fops = { - .owner = THIS_MODULE, - .open = irlmp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - -#endif /* PROC_FS */ diff --git a/drivers/staging/irda/net/irlmp_event.c b/drivers/staging/irda/net/irlmp_event.c deleted file mode 100644 index ddad0994b6dc..000000000000 --- a/drivers/staging/irda/net/irlmp_event.c +++ /dev/null @@ -1,886 +0,0 @@ -/********************************************************************* - * - * Filename: irlmp_event.c - * Version: 0.8 - * Description: An IrDA LMP event driver for Linux - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Tue Dec 14 23:04:16 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/kernel.h> - -#include <net/irda/irda.h> -#include <net/irda/timer.h> -#include <net/irda/irlap.h> -#include <net/irda/irlmp.h> -#include <net/irda/irlmp_frame.h> -#include <net/irda/irlmp_event.h> - -const char *const irlmp_state[] = { - "LAP_STANDBY", - "LAP_U_CONNECT", - "LAP_ACTIVE", -}; - -const char *const irlsap_state[] = { - "LSAP_DISCONNECTED", - "LSAP_CONNECT", - "LSAP_CONNECT_PEND", - "LSAP_DATA_TRANSFER_READY", - "LSAP_SETUP", - "LSAP_SETUP_PEND", -}; - -static const char *const irlmp_event[] __maybe_unused = { - "LM_CONNECT_REQUEST", - "LM_CONNECT_CONFIRM", - "LM_CONNECT_RESPONSE", - "LM_CONNECT_INDICATION", - - "LM_DISCONNECT_INDICATION", - "LM_DISCONNECT_REQUEST", - - "LM_DATA_REQUEST", - "LM_UDATA_REQUEST", - "LM_DATA_INDICATION", - "LM_UDATA_INDICATION", - - "LM_WATCHDOG_TIMEOUT", - - /* IrLAP events */ - "LM_LAP_CONNECT_REQUEST", - "LM_LAP_CONNECT_INDICATION", - "LM_LAP_CONNECT_CONFIRM", - "LM_LAP_DISCONNECT_INDICATION", - "LM_LAP_DISCONNECT_REQUEST", - "LM_LAP_DISCOVERY_REQUEST", - "LM_LAP_DISCOVERY_CONFIRM", - "LM_LAP_IDLE_TIMEOUT", -}; - -/* LAP Connection control proto declarations */ -static void irlmp_state_standby (struct lap_cb *, IRLMP_EVENT, - struct sk_buff *); -static void irlmp_state_u_connect(struct lap_cb *, IRLMP_EVENT, - struct sk_buff *); -static void irlmp_state_active (struct lap_cb *, IRLMP_EVENT, - struct sk_buff *); - -/* LSAP Connection control proto declarations */ -static int irlmp_state_disconnected(struct lsap_cb *, IRLMP_EVENT, - struct sk_buff *); -static int irlmp_state_connect (struct lsap_cb *, IRLMP_EVENT, - struct sk_buff *); -static int irlmp_state_connect_pend(struct lsap_cb *, IRLMP_EVENT, - struct sk_buff *); -static int irlmp_state_dtr (struct lsap_cb *, IRLMP_EVENT, - struct sk_buff *); -static int irlmp_state_setup (struct lsap_cb *, IRLMP_EVENT, - struct sk_buff *); -static int irlmp_state_setup_pend (struct lsap_cb *, IRLMP_EVENT, - struct sk_buff *); - -static void (*lap_state[]) (struct lap_cb *, IRLMP_EVENT, struct sk_buff *) = -{ - irlmp_state_standby, - irlmp_state_u_connect, - irlmp_state_active, -}; - -static int (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) = -{ - irlmp_state_disconnected, - irlmp_state_connect, - irlmp_state_connect_pend, - irlmp_state_dtr, - irlmp_state_setup, - irlmp_state_setup_pend -}; - -static inline void irlmp_next_lap_state(struct lap_cb *self, - IRLMP_STATE state) -{ - /* - pr_debug("%s(), LMP LAP = %s\n", __func__, irlmp_state[state]); - */ - self->lap_state = state; -} - -static inline void irlmp_next_lsap_state(struct lsap_cb *self, - LSAP_STATE state) -{ - /* - IRDA_ASSERT(self != NULL, return;); - pr_debug("%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]); - */ - self->lsap_state = state; -} - -/* Do connection control events */ -int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - - pr_debug("%s(), EVENT = %s, STATE = %s\n", - __func__, irlmp_event[event], irlsap_state[self->lsap_state]); - - return (*lsap_state[self->lsap_state]) (self, event, skb); -} - -/* - * Function do_lap_event (event, skb, info) - * - * Do IrLAP control events - * - */ -void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - - pr_debug("%s(), EVENT = %s, STATE = %s\n", __func__, - irlmp_event[event], - irlmp_state[self->lap_state]); - - (*lap_state[self->lap_state]) (self, event, skb); -} - -void irlmp_discovery_timer_expired(struct timer_list *t) -{ - /* We always cleanup the log (active & passive discovery) */ - irlmp_do_expiry(); - - irlmp_do_discovery(sysctl_discovery_slots); - - /* Restart timer */ - irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout * HZ); -} - -void irlmp_watchdog_timer_expired(struct timer_list *t) -{ - struct lsap_cb *self = from_timer(self, t, watchdog_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - - irlmp_do_lsap_event(self, LM_WATCHDOG_TIMEOUT, NULL); -} - -void irlmp_idle_timer_expired(struct timer_list *t) -{ - struct lap_cb *self = from_timer(self, t, idle_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - - irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL); -} - -/* - * Send an event on all LSAPs attached to this LAP. - */ -static inline void -irlmp_do_all_lsap_event(hashbin_t * lsap_hashbin, - IRLMP_EVENT event) -{ - struct lsap_cb *lsap; - struct lsap_cb *lsap_next; - - /* Note : this function use the new hashbin_find_next() - * function, instead of the old hashbin_get_next(). - * This make sure that we are always pointing one lsap - * ahead, so that if the current lsap is removed as the - * result of sending the event, we don't care. - * Also, as we store the context ourselves, if an enumeration - * of the same lsap hashbin happens as the result of sending the - * event, we don't care. - * The only problem is if the next lsap is removed. In that case, - * hashbin_find_next() will return NULL and we will abort the - * enumeration. - Jean II */ - - /* Also : we don't accept any skb in input. We can *NOT* pass - * the same skb to multiple clients safely, we would need to - * skb_clone() it. - Jean II */ - - lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin); - - while (NULL != hashbin_find_next(lsap_hashbin, - (long) lsap, - NULL, - (void *) &lsap_next) ) { - irlmp_do_lsap_event(lsap, event, NULL); - lsap = lsap_next; - } -} - -/********************************************************************* - * - * LAP connection control states - * - ********************************************************************/ - -/* - * Function irlmp_state_standby (event, skb, info) - * - * STANDBY, The IrLAP connection does not exist. - * - */ -static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - IRDA_ASSERT(self->irlap != NULL, return;); - - switch (event) { - case LM_LAP_DISCOVERY_REQUEST: - /* irlmp_next_station_state( LMP_DISCOVER); */ - - irlap_discovery_request(self->irlap, &irlmp->discovery_cmd); - break; - case LM_LAP_CONNECT_INDICATION: - /* It's important to switch state first, to avoid IrLMP to - * think that the link is free since IrLMP may then start - * discovery before the connection is properly set up. DB. - */ - irlmp_next_lap_state(self, LAP_ACTIVE); - - /* Just accept connection TODO, this should be fixed */ - irlap_connect_response(self->irlap, skb); - break; - case LM_LAP_CONNECT_REQUEST: - pr_debug("%s() LS_CONNECT_REQUEST\n", __func__); - - irlmp_next_lap_state(self, LAP_U_CONNECT); - - /* FIXME: need to set users requested QoS */ - irlap_connect_request(self->irlap, self->daddr, NULL, 0); - break; - case LM_LAP_DISCONNECT_INDICATION: - pr_debug("%s(), Error LM_LAP_DISCONNECT_INDICATION\n", - __func__); - - irlmp_next_lap_state(self, LAP_STANDBY); - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlmp_event[event]); - break; - } -} - -/* - * Function irlmp_state_u_connect (event, skb, info) - * - * U_CONNECT, The layer above has tried to open an LSAP connection but - * since the IrLAP connection does not exist, we must first start an - * IrLAP connection. We are now waiting response from IrLAP. - * */ -static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - pr_debug("%s(), event=%s\n", __func__, irlmp_event[event]); - - switch (event) { - case LM_LAP_CONNECT_INDICATION: - /* It's important to switch state first, to avoid IrLMP to - * think that the link is free since IrLMP may then start - * discovery before the connection is properly set up. DB. - */ - irlmp_next_lap_state(self, LAP_ACTIVE); - - /* Just accept connection TODO, this should be fixed */ - irlap_connect_response(self->irlap, skb); - - /* Tell LSAPs that they can start sending data */ - irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); - - /* Note : by the time we get there (LAP retries and co), - * the lsaps may already have gone. This avoid getting stuck - * forever in LAP_ACTIVE state - Jean II */ - if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - pr_debug("%s() NO LSAPs !\n", __func__); - irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); - } - break; - case LM_LAP_CONNECT_REQUEST: - /* Already trying to connect */ - break; - case LM_LAP_CONNECT_CONFIRM: - /* For all lsap_ce E Associated do LS_Connect_confirm */ - irlmp_next_lap_state(self, LAP_ACTIVE); - - /* Tell LSAPs that they can start sending data */ - irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); - - /* Note : by the time we get there (LAP retries and co), - * the lsaps may already have gone. This avoid getting stuck - * forever in LAP_ACTIVE state - Jean II */ - if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - pr_debug("%s() NO LSAPs !\n", __func__); - irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); - } - break; - case LM_LAP_DISCONNECT_INDICATION: - pr_debug("%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__); - irlmp_next_lap_state(self, LAP_STANDBY); - - /* Send disconnect event to all LSAPs using this link */ - irlmp_do_all_lsap_event(self->lsaps, - LM_LAP_DISCONNECT_INDICATION); - break; - case LM_LAP_DISCONNECT_REQUEST: - pr_debug("%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__); - - /* One of the LSAP did timeout or was closed, if it was - * the last one, try to get out of here - Jean II */ - if (HASHBIN_GET_SIZE(self->lsaps) <= 1) { - irlap_disconnect_request(self->irlap); - } - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlmp_event[event]); - break; - } -} - -/* - * Function irlmp_state_active (event, skb, info) - * - * ACTIVE, IrLAP connection is active - * - */ -static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - switch (event) { - case LM_LAP_CONNECT_REQUEST: - pr_debug("%s(), LS_CONNECT_REQUEST\n", __func__); - - /* - * IrLAP may have a pending disconnect. We tried to close - * IrLAP, but it was postponed because the link was - * busy or we were still sending packets. As we now - * need it, make sure it stays on. Jean II - */ - irlap_clear_disconnect(self->irlap); - - /* - * LAP connection already active, just bounce back! Since we - * don't know which LSAP that tried to do this, we have to - * notify all LSAPs using this LAP, but that should be safe to - * do anyway. - */ - irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM); - - /* Needed by connect indication */ - irlmp_do_all_lsap_event(irlmp->unconnected_lsaps, - LM_LAP_CONNECT_CONFIRM); - /* Keep state */ - break; - case LM_LAP_DISCONNECT_REQUEST: - /* - * Need to find out if we should close IrLAP or not. If there - * is only one LSAP connection left on this link, that LSAP - * must be the one that tries to close IrLAP. It will be - * removed later and moved to the list of unconnected LSAPs - */ - if (HASHBIN_GET_SIZE(self->lsaps) > 0) { - /* Timer value is checked in irsysctl - Jean II */ - irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000); - } else { - /* No more connections, so close IrLAP */ - - /* We don't want to change state just yet, because - * we want to reflect accurately the real state of - * the LAP, not the state we wish it was in, - * so that we don't lose LM_LAP_CONNECT_REQUEST. - * In some cases, IrLAP won't close the LAP - * immediately. For example, it might still be - * retrying packets or waiting for the pf bit. - * As the LAP always send a DISCONNECT_INDICATION - * in PCLOSE or SCLOSE, just change state on that. - * Jean II */ - irlap_disconnect_request(self->irlap); - } - break; - case LM_LAP_IDLE_TIMEOUT: - if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - /* Same reasoning as above - keep state */ - irlap_disconnect_request(self->irlap); - } - break; - case LM_LAP_DISCONNECT_INDICATION: - irlmp_next_lap_state(self, LAP_STANDBY); - - /* In some case, at this point our side has already closed - * all lsaps, and we are waiting for the idle_timer to - * expire. If another device reconnect immediately, the - * idle timer will expire in the midle of the connection - * initialisation, screwing up things a lot... - * Therefore, we must stop the timer... */ - irlmp_stop_idle_timer(self); - - /* - * Inform all connected LSAP's using this link - */ - irlmp_do_all_lsap_event(self->lsaps, - LM_LAP_DISCONNECT_INDICATION); - - /* Force an expiry of the discovery log. - * Now that the LAP is free, the system may attempt to - * connect to another device. Unfortunately, our entries - * are stale. There is a small window (<3s) before the - * normal discovery will run and where irlmp_connect_request() - * can get the wrong info, so make sure things get - * cleaned *NOW* ;-) - Jean II */ - irlmp_do_expiry(); - break; - default: - pr_debug("%s(), Unknown event %s\n", - __func__, irlmp_event[event]); - break; - } -} - -/********************************************************************* - * - * LSAP connection control states - * - ********************************************************************/ - -/* - * Function irlmp_state_disconnected (event, skb, info) - * - * DISCONNECTED - * - */ -static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - - switch (event) { -#ifdef CONFIG_IRDA_ULTRA - case LM_UDATA_INDICATION: - /* This is most bizarre. Those packets are aka unreliable - * connected, aka IrLPT or SOCK_DGRAM/IRDAPROTO_UNITDATA. - * Why do we pass them as Ultra ??? Jean II */ - irlmp_connless_data_indication(self, skb); - break; -#endif /* CONFIG_IRDA_ULTRA */ - case LM_CONNECT_REQUEST: - pr_debug("%s(), LM_CONNECT_REQUEST\n", __func__); - - if (self->conn_skb) { - net_warn_ratelimited("%s: busy with another request!\n", - __func__); - return -EBUSY; - } - /* Don't forget to refcount it (see irlmp_connect_request()) */ - skb_get(skb); - self->conn_skb = skb; - - irlmp_next_lsap_state(self, LSAP_SETUP_PEND); - - /* Start watchdog timer (5 secs for now) */ - irlmp_start_watchdog_timer(self, 5*HZ); - - irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); - break; - case LM_CONNECT_INDICATION: - if (self->conn_skb) { - net_warn_ratelimited("%s: busy with another request!\n", - __func__); - return -EBUSY; - } - /* Don't forget to refcount it (see irlap_driver_rcv()) */ - skb_get(skb); - self->conn_skb = skb; - - irlmp_next_lsap_state(self, LSAP_CONNECT_PEND); - - /* Start watchdog timer - * This is not mentionned in the spec, but there is a rare - * race condition that can get the socket stuck. - * If we receive this event while our LAP is closing down, - * the LM_LAP_CONNECT_REQUEST get lost and we get stuck in - * CONNECT_PEND state forever. - * The other cause of getting stuck down there is if the - * higher layer never reply to the CONNECT_INDICATION. - * Anyway, it make sense to make sure that we always have - * a backup plan. 1 second is plenty (should be immediate). - * Jean II */ - irlmp_start_watchdog_timer(self, 1*HZ); - - irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL); - break; - default: - pr_debug("%s(), Unknown event %s on LSAP %#02x\n", - __func__, irlmp_event[event], self->slsap_sel); - break; - } - return ret; -} - -/* - * Function irlmp_state_connect (self, event, skb) - * - * CONNECT - * - */ -static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - struct lsap_cb *lsap; - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - - switch (event) { - case LM_CONNECT_RESPONSE: - /* - * Bind this LSAP to the IrLAP link where the connect was - * received - */ - lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, - NULL); - - IRDA_ASSERT(lsap == self, return -1;); - IRDA_ASSERT(self->lap != NULL, return -1;); - IRDA_ASSERT(self->lap->lsaps != NULL, return -1;); - - hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, - (long) self, NULL); - - set_bit(0, &self->connected); /* TRUE */ - - irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, - self->slsap_sel, CONNECT_CNF, skb); - - del_timer(&self->watchdog_timer); - - irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY); - break; - case LM_WATCHDOG_TIMEOUT: - /* May happen, who knows... - * Jean II */ - pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__); - - /* Disconnect, get out... - Jean II */ - self->lap = NULL; - self->dlsap_sel = LSAP_ANY; - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - break; - default: - /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we - * are *not* yet bound to the IrLAP link. Jean II */ - pr_debug("%s(), Unknown event %s on LSAP %#02x\n", - __func__, irlmp_event[event], self->slsap_sel); - break; - } - return ret; -} - -/* - * Function irlmp_state_connect_pend (event, skb, info) - * - * CONNECT_PEND - * - */ -static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - struct sk_buff *tx_skb; - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - - switch (event) { - case LM_CONNECT_REQUEST: - /* Keep state */ - break; - case LM_CONNECT_RESPONSE: - pr_debug("%s(), LM_CONNECT_RESPONSE, no indication issued yet\n", - __func__); - /* Keep state */ - break; - case LM_DISCONNECT_REQUEST: - pr_debug("%s(), LM_DISCONNECT_REQUEST, not yet bound to IrLAP connection\n", - __func__); - /* Keep state */ - break; - case LM_LAP_CONNECT_CONFIRM: - pr_debug("%s(), LS_CONNECT_CONFIRM\n", __func__); - irlmp_next_lsap_state(self, LSAP_CONNECT); - - tx_skb = self->conn_skb; - self->conn_skb = NULL; - - irlmp_connect_indication(self, tx_skb); - /* Drop reference count - see irlmp_connect_indication(). */ - dev_kfree_skb(tx_skb); - break; - case LM_WATCHDOG_TIMEOUT: - /* Will happen in some rare cases because of a race condition. - * Just make sure we don't stay there forever... - * Jean II */ - pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__); - - /* Go back to disconnected mode, keep the socket waiting */ - self->lap = NULL; - self->dlsap_sel = LSAP_ANY; - if(self->conn_skb) - dev_kfree_skb(self->conn_skb); - self->conn_skb = NULL; - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - break; - default: - /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we - * are *not* yet bound to the IrLAP link. Jean II */ - pr_debug("%s(), Unknown event %s on LSAP %#02x\n", - __func__, irlmp_event[event], self->slsap_sel); - break; - } - return ret; -} - -/* - * Function irlmp_state_dtr (self, event, skb) - * - * DATA_TRANSFER_READY - * - */ -static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - LM_REASON reason; - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_ASSERT(self->lap != NULL, return -1;); - - switch (event) { - case LM_DATA_REQUEST: /* Optimize for the common case */ - irlmp_send_data_pdu(self->lap, self->dlsap_sel, - self->slsap_sel, FALSE, skb); - break; - case LM_DATA_INDICATION: /* Optimize for the common case */ - irlmp_data_indication(self, skb); - break; - case LM_UDATA_REQUEST: - IRDA_ASSERT(skb != NULL, return -1;); - irlmp_send_data_pdu(self->lap, self->dlsap_sel, - self->slsap_sel, TRUE, skb); - break; - case LM_UDATA_INDICATION: - irlmp_udata_indication(self, skb); - break; - case LM_CONNECT_REQUEST: - pr_debug("%s(), LM_CONNECT_REQUEST, error, LSAP already connected\n", - __func__); - /* Keep state */ - break; - case LM_CONNECT_RESPONSE: - pr_debug("%s(), LM_CONNECT_RESPONSE, error, LSAP already connected\n", - __func__); - /* Keep state */ - break; - case LM_DISCONNECT_REQUEST: - irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, self->slsap_sel, - DISCONNECT, skb); - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - /* Called only from irlmp_disconnect_request(), will - * unbind from LAP over there. Jean II */ - - /* Try to close the LAP connection if its still there */ - if (self->lap) { - pr_debug("%s(), trying to close IrLAP\n", - __func__); - irlmp_do_lap_event(self->lap, - LM_LAP_DISCONNECT_REQUEST, - NULL); - } - break; - case LM_LAP_DISCONNECT_INDICATION: - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - - reason = irlmp_convert_lap_reason(self->lap->reason); - - irlmp_disconnect_indication(self, reason, NULL); - break; - case LM_DISCONNECT_INDICATION: - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - - IRDA_ASSERT(self->lap != NULL, return -1;); - IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); - - IRDA_ASSERT(skb != NULL, return -1;); - IRDA_ASSERT(skb->len > 3, return -1;); - reason = skb->data[3]; - - /* Try to close the LAP connection */ - pr_debug("%s(), trying to close IrLAP\n", __func__); - irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); - - irlmp_disconnect_indication(self, reason, skb); - break; - default: - pr_debug("%s(), Unknown event %s on LSAP %#02x\n", - __func__, irlmp_event[event], self->slsap_sel); - break; - } - return ret; -} - -/* - * Function irlmp_state_setup (event, skb, info) - * - * SETUP, Station Control has set up the underlying IrLAP connection. - * An LSAP connection request has been transmitted to the peer - * LSAP-Connection Control FSM and we are awaiting reply. - */ -static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - LM_REASON reason; - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - - switch (event) { - case LM_CONNECT_CONFIRM: - irlmp_next_lsap_state(self, LSAP_DATA_TRANSFER_READY); - - del_timer(&self->watchdog_timer); - - irlmp_connect_confirm(self, skb); - break; - case LM_DISCONNECT_INDICATION: - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - - IRDA_ASSERT(self->lap != NULL, return -1;); - IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); - - IRDA_ASSERT(skb != NULL, return -1;); - IRDA_ASSERT(skb->len > 3, return -1;); - reason = skb->data[3]; - - /* Try to close the LAP connection */ - pr_debug("%s(), trying to close IrLAP\n", __func__); - irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); - - irlmp_disconnect_indication(self, reason, skb); - break; - case LM_LAP_DISCONNECT_INDICATION: - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - - del_timer(&self->watchdog_timer); - - IRDA_ASSERT(self->lap != NULL, return -1;); - IRDA_ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;); - - reason = irlmp_convert_lap_reason(self->lap->reason); - - irlmp_disconnect_indication(self, reason, skb); - break; - case LM_WATCHDOG_TIMEOUT: - pr_debug("%s() WATCHDOG_TIMEOUT!\n", __func__); - - IRDA_ASSERT(self->lap != NULL, return -1;); - irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - - irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL); - break; - default: - pr_debug("%s(), Unknown event %s on LSAP %#02x\n", - __func__, irlmp_event[event], self->slsap_sel); - break; - } - return ret; -} - -/* - * Function irlmp_state_setup_pend (event, skb, info) - * - * SETUP_PEND, An LM_CONNECT_REQUEST has been received from the service - * user to set up an LSAP connection. A request has been sent to the - * LAP FSM to set up the underlying IrLAP connection, and we - * are awaiting confirm. - */ -static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) -{ - struct sk_buff *tx_skb; - LM_REASON reason; - int ret = 0; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(irlmp != NULL, return -1;); - - switch (event) { - case LM_LAP_CONNECT_CONFIRM: - IRDA_ASSERT(self->conn_skb != NULL, return -1;); - - tx_skb = self->conn_skb; - self->conn_skb = NULL; - - irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, - self->slsap_sel, CONNECT_CMD, tx_skb); - /* Drop reference count - see irlap_data_request(). */ - dev_kfree_skb(tx_skb); - - irlmp_next_lsap_state(self, LSAP_SETUP); - break; - case LM_WATCHDOG_TIMEOUT: - pr_debug("%s() : WATCHDOG_TIMEOUT !\n", __func__); - - IRDA_ASSERT(self->lap != NULL, return -1;); - irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - - irlmp_disconnect_indication(self, LM_CONNECT_FAILURE, NULL); - break; - case LM_LAP_DISCONNECT_INDICATION: /* LS_Disconnect.indication */ - del_timer( &self->watchdog_timer); - - irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - - reason = irlmp_convert_lap_reason(self->lap->reason); - - irlmp_disconnect_indication(self, reason, NULL); - break; - default: - pr_debug("%s(), Unknown event %s on LSAP %#02x\n", - __func__, irlmp_event[event], self->slsap_sel); - break; - } - return ret; -} diff --git a/drivers/staging/irda/net/irlmp_frame.c b/drivers/staging/irda/net/irlmp_frame.c deleted file mode 100644 index 38b0f994bc7b..000000000000 --- a/drivers/staging/irda/net/irlmp_frame.c +++ /dev/null @@ -1,476 +0,0 @@ -/********************************************************************* - * - * Filename: irlmp_frame.c - * Version: 0.9 - * Description: IrLMP frame implementation - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Aug 19 02:09:59 1997 - * Modified at: Mon Dec 13 13:41:12 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no> - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/skbuff.h> -#include <linux/kernel.h> - -#include <net/irda/irda.h> -#include <net/irda/irlap.h> -#include <net/irda/timer.h> -#include <net/irda/irlmp.h> -#include <net/irda/irlmp_frame.h> -#include <net/irda/discovery.h> - -static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap, - __u8 slsap, int status, hashbin_t *); - -inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, - int expedited, struct sk_buff *skb) -{ - skb->data[0] = dlsap; - skb->data[1] = slsap; - - if (expedited) { - pr_debug("%s(), sending expedited data\n", __func__); - irlap_data_request(self->irlap, skb, TRUE); - } else - irlap_data_request(self->irlap, skb, FALSE); -} - -/* - * Function irlmp_send_lcf_pdu (dlsap, slsap, opcode,skb) - * - * Send Link Control Frame to IrLAP - */ -void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, - __u8 opcode, struct sk_buff *skb) -{ - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - frame = skb->data; - - frame[0] = dlsap | CONTROL_BIT; - frame[1] = slsap; - - frame[2] = opcode; - - if (opcode == DISCONNECT) - frame[3] = 0x01; /* Service user request */ - else - frame[3] = 0x00; /* rsvd */ - - irlap_data_request(self->irlap, skb, FALSE); -} - -/* - * Function irlmp_input (skb) - * - * Used by IrLAP to pass received data frames to IrLMP layer - * - */ -void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, - int unreliable) -{ - struct lsap_cb *lsap; - __u8 slsap_sel; /* Source (this) LSAP address */ - __u8 dlsap_sel; /* Destination LSAP address */ - __u8 *fp; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - IRDA_ASSERT(skb->len > 2, return;); - - fp = skb->data; - - /* - * The next statements may be confusing, but we do this so that - * destination LSAP of received frame is source LSAP in our view - */ - slsap_sel = fp[0] & LSAP_MASK; - dlsap_sel = fp[1]; - - /* - * Check if this is an incoming connection, since we must deal with - * it in a different way than other established connections. - */ - if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) { - pr_debug("%s(), incoming connection, source LSAP=%d, dest LSAP=%d\n", - __func__, slsap_sel, dlsap_sel); - - /* Try to find LSAP among the unconnected LSAPs */ - lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD, - irlmp->unconnected_lsaps); - - /* Maybe LSAP was already connected, so try one more time */ - if (!lsap) { - pr_debug("%s(), incoming connection for LSAP already connected\n", - __func__); - lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0, - self->lsaps); - } - } else - lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0, - self->lsaps); - - if (lsap == NULL) { - pr_debug("IrLMP, Sorry, no LSAP for received frame!\n"); - pr_debug("%s(), slsap_sel = %02x, dlsap_sel = %02x\n", - __func__, slsap_sel, dlsap_sel); - if (fp[0] & CONTROL_BIT) { - pr_debug("%s(), received control frame %02x\n", - __func__, fp[2]); - } else { - pr_debug("%s(), received data frame\n", __func__); - } - return; - } - - /* - * Check if we received a control frame? - */ - if (fp[0] & CONTROL_BIT) { - switch (fp[2]) { - case CONNECT_CMD: - lsap->lap = self; - irlmp_do_lsap_event(lsap, LM_CONNECT_INDICATION, skb); - break; - case CONNECT_CNF: - irlmp_do_lsap_event(lsap, LM_CONNECT_CONFIRM, skb); - break; - case DISCONNECT: - pr_debug("%s(), Disconnect indication!\n", - __func__); - irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION, - skb); - break; - case ACCESSMODE_CMD: - pr_debug("Access mode cmd not implemented!\n"); - break; - case ACCESSMODE_CNF: - pr_debug("Access mode cnf not implemented!\n"); - break; - default: - pr_debug("%s(), Unknown control frame %02x\n", - __func__, fp[2]); - break; - } - } else if (unreliable) { - /* Optimize and bypass the state machine if possible */ - if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY) - irlmp_udata_indication(lsap, skb); - else - irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb); - } else { - /* Optimize and bypass the state machine if possible */ - if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY) - irlmp_data_indication(lsap, skb); - else - irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb); - } -} - -/* - * Function irlmp_link_unitdata_indication (self, skb) - * - * - * - */ -#ifdef CONFIG_IRDA_ULTRA -void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) -{ - struct lsap_cb *lsap; - __u8 slsap_sel; /* Source (this) LSAP address */ - __u8 dlsap_sel; /* Destination LSAP address */ - __u8 pid; /* Protocol identifier */ - __u8 *fp; - unsigned long flags; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - IRDA_ASSERT(skb->len > 2, return;); - - fp = skb->data; - - /* - * The next statements may be confusing, but we do this so that - * destination LSAP of received frame is source LSAP in our view - */ - slsap_sel = fp[0] & LSAP_MASK; - dlsap_sel = fp[1]; - pid = fp[2]; - - if (pid & 0x80) { - pr_debug("%s(), extension in PID not supp!\n", - __func__); - return; - } - - /* Check if frame is addressed to the connectionless LSAP */ - if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) { - pr_debug("%s(), dropping frame!\n", __func__); - return; - } - - /* Search the connectionless LSAP */ - spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); - lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps); - while (lsap != NULL) { - /* - * Check if source LSAP and dest LSAP selectors and PID match. - */ - if ((lsap->slsap_sel == slsap_sel) && - (lsap->dlsap_sel == dlsap_sel) && - (lsap->pid == pid)) - { - break; - } - lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps); - } - spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); - - if (lsap) - irlmp_connless_data_indication(lsap, skb); - else { - pr_debug("%s(), found no matching LSAP!\n", __func__); - } -} -#endif /* CONFIG_IRDA_ULTRA */ - -/* - * Function irlmp_link_disconnect_indication (reason, userdata) - * - * IrLAP has disconnected - * - */ -void irlmp_link_disconnect_indication(struct lap_cb *lap, - struct irlap_cb *irlap, - LAP_REASON reason, - struct sk_buff *skb) -{ - IRDA_ASSERT(lap != NULL, return;); - IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); - - lap->reason = reason; - lap->daddr = DEV_ADDR_ANY; - - /* FIXME: must do something with the skb if any */ - - /* - * Inform station state machine - */ - irlmp_do_lap_event(lap, LM_LAP_DISCONNECT_INDICATION, NULL); -} - -/* - * Function irlmp_link_connect_indication (qos) - * - * Incoming LAP connection! - * - */ -void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, - __u32 daddr, struct qos_info *qos, - struct sk_buff *skb) -{ - /* Copy QoS settings for this session */ - self->qos = qos; - - /* Update destination device address */ - self->daddr = daddr; - IRDA_ASSERT(self->saddr == saddr, return;); - - irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb); -} - -/* - * Function irlmp_link_connect_confirm (qos) - * - * LAP connection confirmed! - * - */ -void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, - struct sk_buff *skb) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - IRDA_ASSERT(qos != NULL, return;); - - /* Don't need use the skb for now */ - - /* Copy QoS settings for this session */ - self->qos = qos; - - irlmp_do_lap_event(self, LM_LAP_CONNECT_CONFIRM, NULL); -} - -/* - * Function irlmp_link_discovery_indication (self, log) - * - * Device is discovering us - * - * It's not an answer to our own discoveries, just another device trying - * to perform discovery, but we don't want to miss the opportunity - * to exploit this information, because : - * o We may not actively perform discovery (just passive discovery) - * o This type of discovery is much more reliable. In some cases, it - * seem that less than 50% of our discoveries get an answer, while - * we always get ~100% of these. - * o Make faster discovery, statistically divide time of discovery - * events by 2 (important for the latency aspect and user feel) - * o Even is we do active discovery, the other node might not - * answer our discoveries (ex: Palm). The Palm will just perform - * one active discovery and connect directly to us. - * - * However, when both devices discover each other, they might attempt to - * connect to each other following the discovery event, and it would create - * collisions on the medium (SNRM battle). - * The "fix" for that is to disable all connection requests in IrLAP - * for 100ms after a discovery indication by setting the media_busy flag. - * Previously, we used to postpone the event which was quite ugly. Now - * that IrLAP takes care of this problem, just pass the event up... - * - * Jean II - */ -void irlmp_link_discovery_indication(struct lap_cb *self, - discovery_t *discovery) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - - /* Add to main log, cleanup */ - irlmp_add_discovery(irlmp->cachelog, discovery); - - /* Just handle it the same way as a discovery confirm, - * bypass the LM_LAP state machine (see below) */ - irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_PASSIVE); -} - -/* - * Function irlmp_link_discovery_confirm (self, log) - * - * Called by IrLAP with a list of discoveries after the discovery - * request has been carried out. A NULL log is received if IrLAP - * was unable to carry out the discovery request - * - */ -void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - - /* Add to main log, cleanup */ - irlmp_add_discovery_log(irlmp->cachelog, log); - - /* Propagate event to various LSAPs registered for it. - * We bypass the LM_LAP state machine because - * 1) We do it regardless of the LM_LAP state - * 2) It doesn't affect the LM_LAP state - * 3) Faster, slimer, simpler, ... - * Jean II */ - irlmp_discovery_confirm(irlmp->cachelog, DISCOVERY_ACTIVE); -} - -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP -static inline void irlmp_update_cache(struct lap_cb *lap, - struct lsap_cb *lsap) -{ - /* Prevent concurrent read to get garbage */ - lap->cache.valid = FALSE; - /* Update cache entry */ - lap->cache.dlsap_sel = lsap->dlsap_sel; - lap->cache.slsap_sel = lsap->slsap_sel; - lap->cache.lsap = lsap; - lap->cache.valid = TRUE; -} -#endif - -/* - * Function irlmp_find_handle (self, dlsap_sel, slsap_sel, status, queue) - * - * Find handle associated with destination and source LSAP - * - * Any IrDA connection (LSAP/TSAP) is uniquely identified by - * 3 parameters, the local lsap, the remote lsap and the remote address. - * We may initiate multiple connections to the same remote service - * (they will have different local lsap), a remote device may initiate - * multiple connections to the same local service (they will have - * different remote lsap), or multiple devices may connect to the same - * service and may use the same remote lsap (and they will have - * different remote address). - * So, where is the remote address ? Each LAP connection is made with - * a single remote device, so imply a specific remote address. - * Jean II - */ -static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel, - __u8 slsap_sel, int status, - hashbin_t *queue) -{ - struct lsap_cb *lsap; - unsigned long flags; - - /* - * Optimize for the common case. We assume that the last frame - * received is in the same connection as the last one, so check in - * cache first to avoid the linear search - */ -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - if ((self->cache.valid) && - (self->cache.slsap_sel == slsap_sel) && - (self->cache.dlsap_sel == dlsap_sel)) - { - return self->cache.lsap; - } -#endif - - spin_lock_irqsave(&queue->hb_spinlock, flags); - - lsap = (struct lsap_cb *) hashbin_get_first(queue); - while (lsap != NULL) { - /* - * If this is an incoming connection, then the destination - * LSAP selector may have been specified as LM_ANY so that - * any client can connect. In that case we only need to check - * if the source LSAP (in our view!) match! - */ - if ((status == CONNECT_CMD) && - (lsap->slsap_sel == slsap_sel) && - (lsap->dlsap_sel == LSAP_ANY)) { - /* This is where the dest lsap sel is set on incoming - * lsaps */ - lsap->dlsap_sel = dlsap_sel; - break; - } - /* - * Check if source LSAP and dest LSAP selectors match. - */ - if ((lsap->slsap_sel == slsap_sel) && - (lsap->dlsap_sel == dlsap_sel)) - break; - - lsap = (struct lsap_cb *) hashbin_get_next(queue); - } -#ifdef CONFIG_IRDA_CACHE_LAST_LSAP - if(lsap) - irlmp_update_cache(self, lsap); -#endif - spin_unlock_irqrestore(&queue->hb_spinlock, flags); - - /* Return what we've found or NULL */ - return lsap; -} diff --git a/drivers/staging/irda/net/irmod.c b/drivers/staging/irda/net/irmod.c deleted file mode 100644 index 4319f4ff66b0..000000000000 --- a/drivers/staging/irda/net/irmod.c +++ /dev/null @@ -1,199 +0,0 @@ -/********************************************************************* - * - * Filename: irmod.c - * Version: 0.9 - * Description: IrDA stack main entry points - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Dec 15 13:55:39 1997 - * Modified at: Wed Jan 5 15:12:41 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2004 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -/* - * This file contains the main entry points of the IrDA stack. - * They are in this file and not af_irda.c because some developpers - * are using the IrDA stack without the socket API (compiling out - * af_irda.c). - * Jean II - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> - -#include <net/irda/irda.h> -#include <net/irda/irmod.h> /* notify_t */ -#include <net/irda/irlap.h> /* irlap_init */ -#include <net/irda/irlmp.h> /* irlmp_init */ -#include <net/irda/iriap.h> /* iriap_init */ -#include <net/irda/irttp.h> /* irttp_init */ -#include <net/irda/irda_device.h> /* irda_device_init */ - -/* Packet type handler. - * Tell the kernel how IrDA packets should be handled. - */ -static struct packet_type irda_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_IRDA), - .func = irlap_driver_rcv, /* Packet type handler irlap_frame.c */ -}; - -/* - * Function irda_notify_init (notify) - * - * Used for initializing the notify structure - * - */ -void irda_notify_init(notify_t *notify) -{ - notify->data_indication = NULL; - notify->udata_indication = NULL; - notify->connect_confirm = NULL; - notify->connect_indication = NULL; - notify->disconnect_indication = NULL; - notify->flow_indication = NULL; - notify->status_indication = NULL; - notify->instance = NULL; - strlcpy(notify->name, "Unknown", sizeof(notify->name)); -} -EXPORT_SYMBOL(irda_notify_init); - -/* - * Function irda_init (void) - * - * Protocol stack initialisation entry point. - * Initialise the various components of the IrDA stack - */ -static int __init irda_init(void) -{ - int ret = 0; - - /* Lower layer of the stack */ - irlmp_init(); - irlap_init(); - - /* Driver/dongle support */ - irda_device_init(); - - /* Higher layers of the stack */ - iriap_init(); - irttp_init(); - ret = irsock_init(); - if (ret < 0) - goto out_err_1; - - /* Add IrDA packet type (Start receiving packets) */ - dev_add_pack(&irda_packet_type); - - /* External APIs */ -#ifdef CONFIG_PROC_FS - irda_proc_register(); -#endif -#ifdef CONFIG_SYSCTL - ret = irda_sysctl_register(); - if (ret < 0) - goto out_err_2; -#endif - - ret = irda_nl_register(); - if (ret < 0) - goto out_err_3; - - return 0; - - out_err_3: -#ifdef CONFIG_SYSCTL - irda_sysctl_unregister(); - out_err_2: -#endif -#ifdef CONFIG_PROC_FS - irda_proc_unregister(); -#endif - - /* Remove IrDA packet type (stop receiving packets) */ - dev_remove_pack(&irda_packet_type); - - /* Remove higher layers */ - irsock_cleanup(); - out_err_1: - irttp_cleanup(); - iriap_cleanup(); - - /* Remove lower layers */ - irda_device_cleanup(); - irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */ - - /* Remove middle layer */ - irlmp_cleanup(); - - - return ret; -} - -/* - * Function irda_cleanup (void) - * - * Protocol stack cleanup/removal entry point. - * Cleanup the various components of the IrDA stack - */ -static void __exit irda_cleanup(void) -{ - /* Remove External APIs */ - irda_nl_unregister(); - -#ifdef CONFIG_SYSCTL - irda_sysctl_unregister(); -#endif -#ifdef CONFIG_PROC_FS - irda_proc_unregister(); -#endif - - /* Remove IrDA packet type (stop receiving packets) */ - dev_remove_pack(&irda_packet_type); - - /* Remove higher layers */ - irsock_cleanup(); - irttp_cleanup(); - iriap_cleanup(); - - /* Remove lower layers */ - irda_device_cleanup(); - irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */ - - /* Remove middle layer */ - irlmp_cleanup(); -} - -/* - * The IrDA stack must be initialised *before* drivers get initialised, - * and *before* higher protocols (IrLAN/IrCOMM/IrNET) get initialised, - * otherwise bad things will happen (hashbins will be NULL for example). - * Those modules are at module_init()/device_initcall() level. - * - * On the other hand, it needs to be initialised *after* the basic - * networking, the /proc/net filesystem and sysctl module. Those are - * currently initialised in .../init/main.c (before initcalls). - * Also, IrDA drivers needs to be initialised *after* the random number - * generator (main stack and higher layer init don't need it anymore). - * - * Jean II - */ -device_initcall(irda_init); -module_exit(irda_cleanup); - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> & Jean Tourrilhes <jt@hpl.hp.com>"); -MODULE_DESCRIPTION("The Linux IrDA Protocol Stack"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NETPROTO(PF_IRDA); diff --git a/drivers/staging/irda/net/irnet/Kconfig b/drivers/staging/irda/net/irnet/Kconfig deleted file mode 100644 index 28c557f0fdd2..000000000000 --- a/drivers/staging/irda/net/irnet/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config IRNET - tristate "IrNET protocol" - depends on IRDA && PPP - help - Say Y here if you want to build support for the IrNET protocol. - To compile it as a module, choose M here: the module will be - called irnet. IrNET is a PPP driver, so you will also need a - working PPP subsystem (driver, daemon and config)... - - IrNET is an alternate way to transfer TCP/IP traffic over IrDA. It - uses synchronous PPP over a set of point to point IrDA sockets. You - can use it between Linux machine or with W2k. - diff --git a/drivers/staging/irda/net/irnet/Makefile b/drivers/staging/irda/net/irnet/Makefile deleted file mode 100644 index 61c365c8a2a0..000000000000 --- a/drivers/staging/irda/net/irnet/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the Linux IrDA IrNET protocol layer. -# - -obj-$(CONFIG_IRNET) += irnet.o - -irnet-y := irnet_ppp.o irnet_irda.o diff --git a/drivers/staging/irda/net/irnet/irnet.h b/drivers/staging/irda/net/irnet/irnet.h deleted file mode 100644 index 9d451f8ed47a..000000000000 --- a/drivers/staging/irda/net/irnet/irnet.h +++ /dev/null @@ -1,522 +0,0 @@ -/* - * IrNET protocol module : Synchronous PPP over an IrDA socket. - * - * Jean II - HPL `00 - <jt@hpl.hp.com> - * - * This file contains definitions and declarations global to the IrNET module, - * all grouped in one place... - * This file is a *private* header, so other modules don't want to know - * what's in there... - * - * Note : as most part of the Linux kernel, this module is available - * under the GNU General Public License (GPL). - */ - -#ifndef IRNET_H -#define IRNET_H - -/************************** DOCUMENTATION ***************************/ -/* - * What is IrNET - * ------------- - * IrNET is a protocol allowing to carry TCP/IP traffic between two - * IrDA peers in an efficient fashion. It is a thin layer, passing PPP - * packets to IrTTP and vice versa. It uses PPP in synchronous mode, - * because IrTTP offer a reliable sequenced packet service (as opposed - * to a byte stream). In fact, you could see IrNET as carrying TCP/IP - * in a IrDA socket, using PPP to provide the glue. - * - * The main difference with traditional PPP over IrCOMM is that we - * avoid the framing and serial emulation which are a performance - * bottleneck. It also allows multipoint communications in a sensible - * fashion. - * - * The main difference with IrLAN is that we use PPP for the link - * management, which is more standard, interoperable and flexible than - * the IrLAN protocol. For example, PPP adds authentication, - * encryption, compression, header compression and automated routing - * setup. And, as IrNET let PPP do the hard work, the implementation - * is much simpler than IrLAN. - * - * The Linux implementation - * ------------------------ - * IrNET is written on top of the Linux-IrDA stack, and interface with - * the generic Linux PPP driver. Because IrNET depend on recent - * changes of the PPP driver interface, IrNET will work only with very - * recent kernel (2.3.99-pre6 and up). - * - * The present implementation offer the following features : - * o simple user interface using pppd - * o efficient implementation (interface directly to PPP and IrTTP) - * o addressing (you can specify the name of the IrNET recipient) - * o multipoint operation (limited by IrLAP specification) - * o information in /proc/net/irda/irnet - * o IrNET events on /dev/irnet (for user space daemon) - * o IrNET daemon (irnetd) to automatically handle incoming requests - * o Windows 2000 compatibility (tested, but need more work) - * Currently missing : - * o Lot's of testing (that's your job) - * o Connection retries (may be too hard to do) - * o Check pppd persist mode - * o User space daemon (to automatically handle incoming requests) - * - * The setup is not currently the most easy, but this should get much - * better when everything will get integrated... - * - * Acknowledgements - * ---------------- - * This module is based on : - * o The PPP driver (ppp_synctty/ppp_generic) by Paul Mackerras - * o The IrLAN protocol (irlan_common/XXX) by Dag Brattli - * o The IrSock interface (af_irda) by Dag Brattli - * o Some other bits from the kernel and my drivers... - * Infinite thanks to those brave souls for providing the infrastructure - * upon which IrNET is built. - * - * Thanks to all my colleagues in HP for helping me. In particular, - * thanks to Salil Pradhan and Bill Serra for W2k testing... - * Thanks to Luiz Magalhaes for irnetd and much testing... - * - * Thanks to Alan Cox for answering lot's of my stupid questions, and - * to Paul Mackerras answering my questions on how to best integrate - * IrNET and pppd. - * - * Jean II - * - * Note on some implementations choices... - * ------------------------------------ - * 1) Direct interface vs tty/socket - * I could have used a tty interface to hook to ppp and use the full - * socket API to connect to IrDA. The code would have been easier to - * maintain, and maybe the code would have been smaller... - * Instead, we hook directly to ppp_generic and to IrTTP, which make - * things more complicated... - * - * The first reason is flexibility : this allow us to create IrNET - * instances on demand (no /dev/ircommX crap) and to allow linkname - * specification on pppd command line... - * - * Second reason is speed optimisation. If you look closely at the - * transmit and receive paths, you will notice that they are "super lean" - * (that's why they look ugly), with no function calls and as little data - * copy and modification as I could... - * - * 2) irnetd in user space - * irnetd is implemented in user space, which is necessary to call pppd. - * This also give maximum benefits in term of flexibility and customability, - * and allow to offer the event channel, useful for other stuff like debug. - * - * On the other hand, this require a loose coordination between the - * present module and irnetd. One critical area is how incoming request - * are handled. - * When irnet receive an incoming request, it send an event to irnetd and - * drop the incoming IrNET socket. - * irnetd start a pppd instance, which create a new IrNET socket. This new - * socket is then connected in the originating node to the pppd instance. - * At this point, in the originating node, the first socket is closed. - * - * I admit, this is a bit messy and waste some resources. The alternative - * is caching incoming socket, and that's also quite messy and waste - * resources. - * We also make connection time slower. For example, on a 115 kb/s link it - * adds 60ms to the connection time (770 ms). However, this is slower than - * the time it takes to fire up pppd on my P133... - * - * - * History : - * ------- - * - * v1 - 15.5.00 - Jean II - * o Basic IrNET (hook to ppp_generic & IrTTP - incl. multipoint) - * o control channel on /dev/irnet (set name/address) - * o event channel on /dev/irnet (for user space daemon) - * - * v2 - 5.6.00 - Jean II - * o Enable DROP_NOT_READY to avoid PPP timeouts & other weirdness... - * o Add DISCONNECT_TO event and rename DISCONNECT_FROM. - * o Set official device number alloaction on /dev/irnet - * - * v3 - 30.8.00 - Jean II - * o Update to latest Linux-IrDA changes : - * - queue_t => irda_queue_t - * o Update to ppp-2.4.0 : - * - move irda_irnet_connect from PPPIOCATTACH to TIOCSETD - * o Add EXPIRE event (depend on new IrDA-Linux patch) - * o Switch from `hashbin_remove' to `hashbin_remove_this' to fix - * a multilink bug... (depend on new IrDA-Linux patch) - * o fix a self->daddr to self->raddr in irda_irnet_connect to fix - * another multilink bug (darn !) - * o Remove LINKNAME_IOCTL cruft - * - * v3b - 31.8.00 - Jean II - * o Dump discovery log at event channel startup - * - * v4 - 28.9.00 - Jean II - * o Fix interaction between poll/select and dump discovery log - * o Add IRNET_BLOCKED_LINK event (depend on new IrDA-Linux patch) - * o Add IRNET_NOANSWER_FROM event (mostly to help support) - * o Release flow control in disconnect_indication - * o Block packets while connecting (speed up connections) - * - * v5 - 11.01.01 - Jean II - * o Init self->max_header_size, just in case... - * o Set up ap->chan.hdrlen, to get zero copy on tx side working. - * o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state - * Thanks to Christian Gennerat for finding this bug ! - * --- - * o Declare the proper MTU/MRU that we can support - * (but PPP doesn't read the MTU value :-() - * o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid - * disabling and enabling irq twice - * - * v6 - 31.05.01 - Jean II - * o Print source address in Found, Discovery, Expiry & Request events - * o Print requested source address in /proc/net/irnet - * o Change control channel input. Allow multiple commands in one line. - * o Add saddr command to change ap->rsaddr (and use that in IrDA) - * --- - * o Make the IrDA connection procedure totally asynchronous. - * Heavy rewrite of the IAS query code and the whole connection - * procedure. Now, irnet_connect() no longer need to be called from - * a process context... - * o Enable IrDA connect retries in ppp_irnet_send(). The good thing - * is that IrDA connect retries are directly driven by PPP LCP - * retries (we retry for each LCP packet), so that everything - * is transparently controlled from pppd lcp-max-configure. - * o Add ttp_connect flag to prevent rentry on the connect procedure - * o Test and fixups to eliminate side effects of retries - * - * v7 - 22.08.01 - Jean II - * o Cleanup : Change "saddr = 0x0" to "saddr = DEV_ADDR_ANY" - * o Fix bug in BLOCK_WHEN_CONNECT introduced in v6 : due to the - * asynchronous IAS query, self->tsap is NULL when PPP send the - * first packet. This was preventing "connect-delay 0" to work. - * Change the test in ppp_irnet_send() to self->ttp_connect. - * - * v8 - 1.11.01 - Jean II - * o Tighten the use of self->ttp_connect and self->ttp_open to - * prevent various race conditions. - * o Avoid leaking discovery log and skb - * o Replace "self" with "server" in irnet_connect_indication() to - * better detect cut'n'paste error ;-) - * - * v9 - 29.11.01 - Jean II - * o Fix event generation in disconnect indication that I broke in v8 - * It was always generation "No-Answer" because I was testing ttp_open - * just after clearing it. *blush*. - * o Use newly created irttp_listen() to fix potential crash when LAP - * destroyed before irnet module removed. - * - * v10 - 4.3.2 - Jean II - * o When receiving a disconnect indication, don't reenable the - * PPP Tx queue, this will trigger a reconnect. Instead, close - * the channel, which will kill pppd... - * - * v11 - 20.3.02 - Jean II - * o Oops ! v10 fix disabled IrNET retries and passive behaviour. - * Better fix in irnet_disconnect_indication() : - * - if connected, kill pppd via hangup. - * - if not connected, reenable ppp Tx, which trigger IrNET retry. - * - * v12 - 10.4.02 - Jean II - * o Fix race condition in irnet_connect_indication(). - * If the socket was already trying to connect, drop old connection - * and use new one only if acting as primary. See comments. - * - * v13 - 30.5.02 - Jean II - * o Update module init code - * - * v14 - 20.2.03 - Jean II - * o Add discovery hint bits in the control channel. - * o Remove obsolete MOD_INC/DEC_USE_COUNT in favor of .owner - * - * v15 - 7.4.03 - Jean II - * o Replace spin_lock_irqsave() with spin_lock_bh() so that we can - * use ppp_unit_number(). It's probably also better overall... - * o Disable call to ppp_unregister_channel(), because we can't do it. - */ - -/***************************** INCLUDES *****************************/ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/tty.h> -#include <linux/proc_fs.h> -#include <linux/netdevice.h> -#include <linux/poll.h> -#include <linux/capability.h> -#include <linux/ctype.h> /* isspace() */ -#include <linux/string.h> /* skip_spaces() */ -#include <linux/uaccess.h> -#include <linux/init.h> - -#include <linux/ppp_defs.h> -#include <linux/ppp-ioctl.h> -#include <linux/ppp_channel.h> - -#include <net/irda/irda.h> -#include <net/irda/iriap.h> -#include <net/irda/irias_object.h> -#include <net/irda/irlmp.h> -#include <net/irda/irttp.h> -#include <net/irda/discovery.h> - -/***************************** OPTIONS *****************************/ -/* - * Define or undefine to compile or not some optional part of the - * IrNET driver... - * Note : the present defaults make sense, play with that at your - * own risk... - */ -/* IrDA side of the business... */ -#define DISCOVERY_NOMASK /* To enable W2k compatibility... */ -#define ADVERTISE_HINT /* Advertise IrLAN hint bit */ -#define ALLOW_SIMULT_CONNECT /* This seem to work, cross fingers... */ -#define DISCOVERY_EVENTS /* Query the discovery log to post events */ -#define INITIAL_DISCOVERY /* Dump current discovery log as events */ -#undef STREAM_COMPAT /* Not needed - potentially messy */ -#undef CONNECT_INDIC_KICK /* Might mess IrDA, not needed */ -#undef FAIL_SEND_DISCONNECT /* Might mess IrDA, not needed */ -#undef PASS_CONNECT_PACKETS /* Not needed ? Safe */ -#undef MISSING_PPP_API /* Stuff I wish I could do */ - -/* PPP side of the business */ -#define BLOCK_WHEN_CONNECT /* Block packets when connecting */ -#define CONNECT_IN_SEND /* Retry IrDA connection procedure */ -#undef FLUSH_TO_PPP /* Not sure about this one, let's play safe */ -#undef SECURE_DEVIRNET /* Bah... */ - -/****************************** DEBUG ******************************/ - -/* - * This set of flags enable and disable all the various warning, - * error and debug message of this driver. - * Each section can be enabled and disabled independently - */ -/* In the PPP part */ -#define DEBUG_CTRL_TRACE 0 /* Control channel */ -#define DEBUG_CTRL_INFO 0 /* various info */ -#define DEBUG_CTRL_ERROR 1 /* problems */ -#define DEBUG_FS_TRACE 0 /* filesystem callbacks */ -#define DEBUG_FS_INFO 0 /* various info */ -#define DEBUG_FS_ERROR 1 /* problems */ -#define DEBUG_PPP_TRACE 0 /* PPP related functions */ -#define DEBUG_PPP_INFO 0 /* various info */ -#define DEBUG_PPP_ERROR 1 /* problems */ -#define DEBUG_MODULE_TRACE 0 /* module insertion/removal */ -#define DEBUG_MODULE_ERROR 1 /* problems */ - -/* In the IrDA part */ -#define DEBUG_IRDA_SR_TRACE 0 /* IRDA subroutines */ -#define DEBUG_IRDA_SR_INFO 0 /* various info */ -#define DEBUG_IRDA_SR_ERROR 1 /* problems */ -#define DEBUG_IRDA_SOCK_TRACE 0 /* IRDA main socket functions */ -#define DEBUG_IRDA_SOCK_INFO 0 /* various info */ -#define DEBUG_IRDA_SOCK_ERROR 1 /* problems */ -#define DEBUG_IRDA_SERV_TRACE 0 /* The IrNET server */ -#define DEBUG_IRDA_SERV_INFO 0 /* various info */ -#define DEBUG_IRDA_SERV_ERROR 1 /* problems */ -#define DEBUG_IRDA_TCB_TRACE 0 /* IRDA IrTTP callbacks */ -#define DEBUG_IRDA_CB_INFO 0 /* various info */ -#define DEBUG_IRDA_CB_ERROR 1 /* problems */ -#define DEBUG_IRDA_OCB_TRACE 0 /* IRDA other callbacks */ -#define DEBUG_IRDA_OCB_INFO 0 /* various info */ -#define DEBUG_IRDA_OCB_ERROR 1 /* problems */ - -#define DEBUG_ASSERT 0 /* Verify all assertions */ - -/* - * These are the macros we are using to actually print the debug - * statements. Don't look at it, it's ugly... - * - * One of the trick is that, as the DEBUG_XXX are constant, the - * compiler will optimise away the if() in all cases. - */ -/* All error messages (will show up in the normal logs) */ -#define DERROR(dbg, format, args...) \ - {if(DEBUG_##dbg) \ - printk(KERN_INFO "irnet: %s(): " format, __func__ , ##args);} - -/* Normal debug message (will show up in /var/log/debug) */ -#define DEBUG(dbg, format, args...) \ - {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: %s(): " format, __func__ , ##args);} - -/* Entering a function (trace) */ -#define DENTER(dbg, format, args...) \ - {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: -> %s" format, __func__ , ##args);} - -/* Entering and exiting a function in one go (trace) */ -#define DPASS(dbg, format, args...) \ - {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: <>%s" format, __func__ , ##args);} - -/* Exiting a function (trace) */ -#define DEXIT(dbg, format, args...) \ - {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: <-%s()" format, __func__ , ##args);} - -/* Exit a function with debug */ -#define DRETURN(ret, dbg, args...) \ - {DEXIT(dbg, ": " args);\ - return ret; } - -/* Exit a function on failed condition */ -#define DABORT(cond, ret, dbg, args...) \ - {if(cond) {\ - DERROR(dbg, args);\ - return ret; }} - -/* Invalid assertion, print out an error and exit... */ -#define DASSERT(cond, ret, dbg, args...) \ - {if((DEBUG_ASSERT) && !(cond)) {\ - DERROR(dbg, "Invalid assertion: " args);\ - return ret; }} - -/************************ CONSTANTS & MACROS ************************/ - -/* Paranoia */ -#define IRNET_MAGIC 0xB00754 - -/* Number of control events in the control channel buffer... */ -#define IRNET_MAX_EVENTS 8 /* Should be more than enough... */ - -/****************************** TYPES ******************************/ - -/* - * This is the main structure where we store all the data pertaining to - * one instance of irnet. - * Note : in irnet functions, a pointer this structure is usually called - * "ap" or "self". If the code is borrowed from the IrDA stack, it tend - * to be called "self", and if it is borrowed from the PPP driver it is - * "ap". Apart from that, it's exactly the same structure ;-) - */ -typedef struct irnet_socket -{ - /* ------------------- Instance management ------------------- */ - /* We manage a linked list of IrNET socket instances */ - irda_queue_t q; /* Must be first - for hasbin */ - int magic; /* Paranoia */ - - /* --------------------- FileSystem part --------------------- */ - /* "pppd" interact directly with us on a /dev/ file */ - struct file * file; /* File descriptor of this instance */ - /* TTY stuff - to keep "pppd" happy */ - struct ktermios termios; /* Various tty flags */ - /* Stuff for the control channel */ - int event_index; /* Last read in the event log */ - - /* ------------------------- PPP part ------------------------- */ - /* We interface directly to the ppp_generic driver in the kernel */ - int ppp_open; /* registered with ppp_generic */ - struct ppp_channel chan; /* Interface to generic ppp layer */ - - int mru; /* Max size of PPP payload */ - u32 xaccm[8]; /* Asynchronous character map (just */ - u32 raccm; /* to please pppd - dummy) */ - unsigned int flags; /* PPP flags (compression, ...) */ - unsigned int rbits; /* Unused receive flags ??? */ - struct work_struct disconnect_work; /* Process context disconnection */ - /* ------------------------ IrTTP part ------------------------ */ - /* We create a pseudo "socket" over the IrDA tranport */ - unsigned long ttp_open; /* Set when IrTTP is ready */ - unsigned long ttp_connect; /* Set when IrTTP is connecting */ - struct tsap_cb * tsap; /* IrTTP instance (the connection) */ - - char rname[NICKNAME_MAX_LEN + 1]; - /* IrDA nickname of destination */ - __u32 rdaddr; /* Requested peer IrDA address */ - __u32 rsaddr; /* Requested local IrDA address */ - __u32 daddr; /* actual peer IrDA address */ - __u32 saddr; /* my local IrDA address */ - __u8 dtsap_sel; /* Remote TSAP selector */ - __u8 stsap_sel; /* Local TSAP selector */ - - __u32 max_sdu_size_rx;/* Socket parameters used for IrTTP */ - __u32 max_sdu_size_tx; - __u32 max_data_size; - __u8 max_header_size; - LOCAL_FLOW tx_flow; /* State of the Tx path in IrTTP */ - - /* ------------------- IrLMP and IrIAS part ------------------- */ - /* Used for IrDA Discovery and socket name resolution */ - void * ckey; /* IrLMP client handle */ - __u16 mask; /* Hint bits mask (filter discov.)*/ - int nslots; /* Number of slots for discovery */ - - struct iriap_cb * iriap; /* Used to query remote IAS */ - int errno; /* status of the IAS query */ - - /* -------------------- Discovery log part -------------------- */ - /* Used by initial discovery on the control channel - * and by irnet_discover_daddr_and_lsap_sel() */ - struct irda_device_info *discoveries; /* Copy of the discovery log */ - int disco_index; /* Last read in the discovery log */ - int disco_number; /* Size of the discovery log */ - - struct mutex lock; - -} irnet_socket; - -/* - * This is the various event that we will generate on the control channel - */ -typedef enum irnet_event -{ - IRNET_DISCOVER, /* New IrNET node discovered */ - IRNET_EXPIRE, /* IrNET node expired */ - IRNET_CONNECT_TO, /* IrNET socket has connected to other node */ - IRNET_CONNECT_FROM, /* Other node has connected to IrNET socket */ - IRNET_REQUEST_FROM, /* Non satisfied connection request */ - IRNET_NOANSWER_FROM, /* Failed connection request */ - IRNET_BLOCKED_LINK, /* Link (IrLAP) is blocked for > 3s */ - IRNET_DISCONNECT_FROM, /* IrNET socket has disconnected */ - IRNET_DISCONNECT_TO /* Closing IrNET socket */ -} irnet_event; - -/* - * This is the storage for an event and its arguments - */ -typedef struct irnet_log -{ - irnet_event event; - int unit; - __u32 saddr; - __u32 daddr; - char name[NICKNAME_MAX_LEN + 1]; /* 21 + 1 */ - __u16_host_order hints; /* Discovery hint bits */ -} irnet_log; - -/* - * This is the storage for all events and related stuff... - */ -typedef struct irnet_ctrl_channel -{ - irnet_log log[IRNET_MAX_EVENTS]; /* Event log */ - int index; /* Current index in log */ - spinlock_t spinlock; /* Serialize access to the event log */ - wait_queue_head_t rwait; /* processes blocked on read (or poll) */ -} irnet_ctrl_channel; - -/**************************** PROTOTYPES ****************************/ -/* - * Global functions of the IrNET module - * Note : we list here also functions called from one file to the other. - */ - -/* -------------------------- IRDA PART -------------------------- */ -int irda_irnet_create(irnet_socket *); /* Initialise an IrNET socket */ -int irda_irnet_connect(irnet_socket *); /* Try to connect over IrDA */ -void irda_irnet_destroy(irnet_socket *); /* Teardown an IrNET socket */ -int irda_irnet_init(void); /* Initialise IrDA part of IrNET */ -void irda_irnet_cleanup(void); /* Teardown IrDA part of IrNET */ - -/**************************** VARIABLES ****************************/ - -/* Control channel stuff - allocated in irnet_irda.h */ -extern struct irnet_ctrl_channel irnet_events; - -#endif /* IRNET_H */ diff --git a/drivers/staging/irda/net/irnet/irnet_irda.c b/drivers/staging/irda/net/irnet/irnet_irda.c deleted file mode 100644 index e390bceeb2f8..000000000000 --- a/drivers/staging/irda/net/irnet/irnet_irda.c +++ /dev/null @@ -1,1885 +0,0 @@ -/* - * IrNET protocol module : Synchronous PPP over an IrDA socket. - * - * Jean II - HPL `00 - <jt@hpl.hp.com> - * - * This file implement the IRDA interface of IrNET. - * Basically, we sit on top of IrTTP. We set up IrTTP, IrIAS properly, - * and exchange frames with IrTTP. - */ - -#include "irnet_irda.h" /* Private header */ -#include <linux/sched.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <asm/unaligned.h> - -/* - * PPP disconnect work: we need to make sure we're in - * process context when calling ppp_unregister_channel(). - */ -static void irnet_ppp_disconnect(struct work_struct *work) -{ - irnet_socket * self = - container_of(work, irnet_socket, disconnect_work); - - if (self == NULL) - return; - /* - * If we were connected, cleanup & close the PPP - * channel, which will kill pppd (hangup) and the rest. - */ - if (self->ppp_open && !self->ttp_open && !self->ttp_connect) { - ppp_unregister_channel(&self->chan); - self->ppp_open = 0; - } -} - -/************************* CONTROL CHANNEL *************************/ -/* - * When ppp is not active, /dev/irnet act as a control channel. - * Writing allow to set up the IrDA destination of the IrNET channel, - * and any application may be read events happening on IrNET... - */ - -/*------------------------------------------------------------------*/ -/* - * Post an event to the control channel... - * Put the event in the log, and then wait all process blocked on read - * so they can read the log... - */ -static void -irnet_post_event(irnet_socket * ap, - irnet_event event, - __u32 saddr, - __u32 daddr, - char * name, - __u16 hints) -{ - int index; /* In the log */ - - DENTER(CTRL_TRACE, "(ap=0x%p, event=%d, daddr=%08x, name=``%s'')\n", - ap, event, daddr, name); - - /* Protect this section via spinlock. - * Note : as we are the only event producer, we only need to exclude - * ourself when touching the log, which is nice and easy. - */ - spin_lock_bh(&irnet_events.spinlock); - - /* Copy the event in the log */ - index = irnet_events.index; - irnet_events.log[index].event = event; - irnet_events.log[index].daddr = daddr; - irnet_events.log[index].saddr = saddr; - /* Try to copy IrDA nickname */ - if(name) - strcpy(irnet_events.log[index].name, name); - else - irnet_events.log[index].name[0] = '\0'; - /* Copy hints */ - irnet_events.log[index].hints.word = hints; - /* Try to get ppp unit number */ - if((ap != (irnet_socket *) NULL) && (ap->ppp_open)) - irnet_events.log[index].unit = ppp_unit_number(&ap->chan); - else - irnet_events.log[index].unit = -1; - - /* Increment the index - * Note that we increment the index only after the event is written, - * to make sure that the readers don't get garbage... */ - irnet_events.index = (index + 1) % IRNET_MAX_EVENTS; - - DEBUG(CTRL_INFO, "New event index is %d\n", irnet_events.index); - - /* Spin lock end */ - spin_unlock_bh(&irnet_events.spinlock); - - /* Now : wake up everybody waiting for events... */ - wake_up_interruptible_all(&irnet_events.rwait); - - DEXIT(CTRL_TRACE, "\n"); -} - -/************************* IRDA SUBROUTINES *************************/ -/* - * These are a bunch of subroutines called from other functions - * down there, mostly common code or to improve readability... - * - * Note : we duplicate quite heavily some routines of af_irda.c, - * because our input structure (self) is quite different - * (struct irnet instead of struct irda_sock), which make sharing - * the same code impossible (at least, without templates). - */ - -/*------------------------------------------------------------------*/ -/* - * Function irda_open_tsap (self) - * - * Open local Transport Service Access Point (TSAP) - * - * Create a IrTTP instance for us and set all the IrTTP callbacks. - */ -static inline int -irnet_open_tsap(irnet_socket * self) -{ - notify_t notify; /* Callback structure */ - - DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); - - DABORT(self->tsap != NULL, -EBUSY, IRDA_SR_ERROR, "Already busy !\n"); - - /* Initialize IrTTP callbacks to be used by the IrDA stack */ - irda_notify_init(¬ify); - notify.connect_confirm = irnet_connect_confirm; - notify.connect_indication = irnet_connect_indication; - notify.disconnect_indication = irnet_disconnect_indication; - notify.data_indication = irnet_data_indication; - /*notify.udata_indication = NULL;*/ - notify.flow_indication = irnet_flow_indication; - notify.status_indication = irnet_status_indication; - notify.instance = self; - strlcpy(notify.name, IRNET_NOTIFY_NAME, sizeof(notify.name)); - - /* Open an IrTTP instance */ - self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, - ¬ify); - DABORT(self->tsap == NULL, -ENOMEM, - IRDA_SR_ERROR, "Unable to allocate TSAP !\n"); - - /* Remember which TSAP selector we actually got */ - self->stsap_sel = self->tsap->stsap_sel; - - DEXIT(IRDA_SR_TRACE, " - tsap=0x%p, sel=0x%X\n", - self->tsap, self->stsap_sel); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_ias_to_tsap (self, result, value) - * - * Examine an IAS object and extract TSAP - * - * We do an IAP query to find the TSAP associated with the IrNET service. - * When IrIAP pass us the result of the query, this function look at - * the return values to check for failures and extract the TSAP if - * possible. - * Also deallocate value - * The failure is in self->errno - * Return TSAP or -1 - */ -static inline __u8 -irnet_ias_to_tsap(irnet_socket * self, - int result, - struct ias_value * value) -{ - __u8 dtsap_sel = 0; /* TSAP we are looking for */ - - DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); - - /* By default, no error */ - self->errno = 0; - - /* Check if request succeeded */ - switch(result) - { - /* Standard errors : service not available */ - case IAS_CLASS_UNKNOWN: - case IAS_ATTRIB_UNKNOWN: - DEBUG(IRDA_SR_INFO, "IAS object doesn't exist ! (%d)\n", result); - self->errno = -EADDRNOTAVAIL; - break; - - /* Other errors, most likely IrDA stack failure */ - default : - DEBUG(IRDA_SR_INFO, "IAS query failed ! (%d)\n", result); - self->errno = -EHOSTUNREACH; - break; - - /* Success : we got what we wanted */ - case IAS_SUCCESS: - break; - } - - /* Check what was returned to us */ - if(value != NULL) - { - /* What type of argument have we got ? */ - switch(value->type) - { - case IAS_INTEGER: - DEBUG(IRDA_SR_INFO, "result=%d\n", value->t.integer); - if(value->t.integer != -1) - /* Get the remote TSAP selector */ - dtsap_sel = value->t.integer; - else - self->errno = -EADDRNOTAVAIL; - break; - default: - self->errno = -EADDRNOTAVAIL; - DERROR(IRDA_SR_ERROR, "bad type ! (0x%X)\n", value->type); - break; - } - - /* Cleanup */ - irias_delete_value(value); - } - else /* value == NULL */ - { - /* Nothing returned to us - usually result != SUCCESS */ - if(!(self->errno)) - { - DERROR(IRDA_SR_ERROR, - "IrDA bug : result == SUCCESS && value == NULL\n"); - self->errno = -EHOSTUNREACH; - } - } - DEXIT(IRDA_SR_TRACE, "\n"); - - /* Return the TSAP */ - return dtsap_sel; -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_find_lsap_sel (self) - * - * Try to lookup LSAP selector in remote LM-IAS - * - * Basically, we start a IAP query, and then go to sleep. When the query - * return, irnet_getvalue_confirm will wake us up, and we can examine the - * result of the query... - * Note that in some case, the query fail even before we go to sleep, - * creating some races... - */ -static inline int -irnet_find_lsap_sel(irnet_socket * self) -{ - DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); - - /* This should not happen */ - DABORT(self->iriap, -EBUSY, IRDA_SR_ERROR, "busy with a previous query.\n"); - - /* Create an IAP instance, will be closed in irnet_getvalue_confirm() */ - self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - irnet_getvalue_confirm); - - /* Treat unexpected signals as disconnect */ - self->errno = -EHOSTUNREACH; - - /* Query remote LM-IAS */ - iriap_getvaluebyclass_request(self->iriap, self->rsaddr, self->daddr, - IRNET_SERVICE_NAME, IRNET_IAS_VALUE); - - /* The above request is non-blocking. - * After a while, IrDA will call us back in irnet_getvalue_confirm() - * We will then call irnet_ias_to_tsap() and finish the - * connection procedure */ - - DEXIT(IRDA_SR_TRACE, "\n"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_connect_tsap (self) - * - * Initialise the TTP socket and initiate TTP connection - * - */ -static inline int -irnet_connect_tsap(irnet_socket * self) -{ - int err; - - DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); - - /* Open a local TSAP (an IrTTP instance) */ - err = irnet_open_tsap(self); - if(err != 0) - { - clear_bit(0, &self->ttp_connect); - DERROR(IRDA_SR_ERROR, "connect aborted!\n"); - return err; - } - - /* Connect to remote device */ - err = irttp_connect_request(self->tsap, self->dtsap_sel, - self->rsaddr, self->daddr, NULL, - self->max_sdu_size_rx, NULL); - if(err != 0) - { - clear_bit(0, &self->ttp_connect); - DERROR(IRDA_SR_ERROR, "connect aborted!\n"); - return err; - } - - /* The above call is non-blocking. - * After a while, the IrDA stack will either call us back in - * irnet_connect_confirm() or irnet_disconnect_indication() - * See you there ;-) */ - - DEXIT(IRDA_SR_TRACE, "\n"); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_discover_next_daddr (self) - * - * Query the IrNET TSAP of the next device in the log. - * - * Used in the TSAP discovery procedure. - */ -static inline int -irnet_discover_next_daddr(irnet_socket * self) -{ - /* Close the last instance of IrIAP, and open a new one. - * We can't reuse the IrIAP instance in the IrIAP callback */ - if(self->iriap) - { - iriap_close(self->iriap); - self->iriap = NULL; - } - /* Create a new IAP instance */ - self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self, - irnet_discovervalue_confirm); - if(self->iriap == NULL) - return -ENOMEM; - - /* Next discovery - before the call to avoid races */ - self->disco_index++; - - /* Check if we have one more address to try */ - if(self->disco_index < self->disco_number) - { - /* Query remote LM-IAS */ - iriap_getvaluebyclass_request(self->iriap, - self->discoveries[self->disco_index].saddr, - self->discoveries[self->disco_index].daddr, - IRNET_SERVICE_NAME, IRNET_IAS_VALUE); - /* The above request is non-blocking. - * After a while, IrDA will call us back in irnet_discovervalue_confirm() - * We will then call irnet_ias_to_tsap() and come back here again... */ - return 0; - } - else - return 1; -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_discover_daddr_and_lsap_sel (self) - * - * This try to find a device with the requested service. - * - * Initiate a TSAP discovery procedure. - * It basically look into the discovery log. For each address in the list, - * it queries the LM-IAS of the device to find if this device offer - * the requested service. - * If there is more than one node supporting the service, we complain - * to the user (it should move devices around). - * If we find one node which have the requested TSAP, we connect to it. - * - * This function just start the whole procedure. It request the discovery - * log and submit the first IAS query. - * The bulk of the job is handled in irnet_discovervalue_confirm() - * - * Note : this procedure fails if there is more than one device in range - * on the same dongle, because IrLMP doesn't disconnect the LAP when the - * last LSAP is closed. Moreover, we would need to wait the LAP - * disconnection... - */ -static inline int -irnet_discover_daddr_and_lsap_sel(irnet_socket * self) -{ - int ret; - - DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); - - /* Ask lmp for the current discovery log */ - self->discoveries = irlmp_get_discoveries(&self->disco_number, self->mask, - DISCOVERY_DEFAULT_SLOTS); - - /* Check if the we got some results */ - if(self->discoveries == NULL) - { - self->disco_number = -1; - clear_bit(0, &self->ttp_connect); - DRETURN(-ENETUNREACH, IRDA_SR_INFO, "No Cachelog...\n"); - } - DEBUG(IRDA_SR_INFO, "Got the log (0x%p), size is %d\n", - self->discoveries, self->disco_number); - - /* Start with the first discovery */ - self->disco_index = -1; - self->daddr = DEV_ADDR_ANY; - - /* This will fail if the log is empty - this is non-blocking */ - ret = irnet_discover_next_daddr(self); - if(ret) - { - /* Close IAP */ - if(self->iriap) - iriap_close(self->iriap); - self->iriap = NULL; - - /* Cleanup our copy of the discovery log */ - kfree(self->discoveries); - self->discoveries = NULL; - - clear_bit(0, &self->ttp_connect); - DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); - } - - /* Follow me in irnet_discovervalue_confirm() */ - - DEXIT(IRDA_SR_TRACE, "\n"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_dname_to_daddr (self) - * - * Convert an IrDA nickname to a valid IrDA address - * - * It basically look into the discovery log until there is a match. - */ -static inline int -irnet_dname_to_daddr(irnet_socket * self) -{ - struct irda_device_info *discoveries; /* Copy of the discovery log */ - int number; /* Number of nodes in the log */ - int i; - - DENTER(IRDA_SR_TRACE, "(self=0x%p)\n", self); - - /* Ask lmp for the current discovery log */ - discoveries = irlmp_get_discoveries(&number, 0xffff, - DISCOVERY_DEFAULT_SLOTS); - /* Check if the we got some results */ - if(discoveries == NULL) - DRETURN(-ENETUNREACH, IRDA_SR_INFO, "Cachelog empty...\n"); - - /* - * Now, check all discovered devices (if any), and connect - * client only about the services that the client is - * interested in... - */ - for(i = 0; i < number; i++) - { - /* Does the name match ? */ - if(!strncmp(discoveries[i].info, self->rname, NICKNAME_MAX_LEN)) - { - /* Yes !!! Get it.. */ - self->daddr = discoveries[i].daddr; - DEBUG(IRDA_SR_INFO, "discovered device ``%s'' at address 0x%08x.\n", - self->rname, self->daddr); - kfree(discoveries); - DEXIT(IRDA_SR_TRACE, "\n"); - return 0; - } - } - /* No luck ! */ - DEBUG(IRDA_SR_INFO, "cannot discover device ``%s'' !!!\n", self->rname); - kfree(discoveries); - return -EADDRNOTAVAIL; -} - - -/************************* SOCKET ROUTINES *************************/ -/* - * This are the main operations on IrNET sockets, basically to create - * and destroy IrNET sockets. These are called from the PPP part... - */ - -/*------------------------------------------------------------------*/ -/* - * Create a IrNET instance : just initialise some parameters... - */ -int -irda_irnet_create(irnet_socket * self) -{ - DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); - - self->magic = IRNET_MAGIC; /* Paranoia */ - - self->ttp_open = 0; /* Prevent higher layer from accessing IrTTP */ - self->ttp_connect = 0; /* Not connecting yet */ - self->rname[0] = '\0'; /* May be set via control channel */ - self->rdaddr = DEV_ADDR_ANY; /* May be set via control channel */ - self->rsaddr = DEV_ADDR_ANY; /* May be set via control channel */ - self->daddr = DEV_ADDR_ANY; /* Until we get connected */ - self->saddr = DEV_ADDR_ANY; /* Until we get connected */ - self->max_sdu_size_rx = TTP_SAR_UNBOUND; - - /* Register as a client with IrLMP */ - self->ckey = irlmp_register_client(0, NULL, NULL, NULL); -#ifdef DISCOVERY_NOMASK - self->mask = 0xffff; /* For W2k compatibility */ -#else /* DISCOVERY_NOMASK */ - self->mask = irlmp_service_to_hint(S_LAN); -#endif /* DISCOVERY_NOMASK */ - self->tx_flow = FLOW_START; /* Flow control from IrTTP */ - - INIT_WORK(&self->disconnect_work, irnet_ppp_disconnect); - - DEXIT(IRDA_SOCK_TRACE, "\n"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Connect to the other side : - * o convert device name to an address - * o find the socket number (dlsap) - * o Establish the connection - * - * Note : We no longer mimic af_irda. The IAS query for finding the TSAP - * is done asynchronously, like the TTP connection. This allow us to - * call this function from any context (not only process). - * The downside is that following what's happening in there is tricky - * because it involve various functions all over the place... - */ -int -irda_irnet_connect(irnet_socket * self) -{ - int err; - - DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); - - /* Check if we are already trying to connect. - * Because irda_irnet_connect() can be called directly by pppd plus - * packet retries in ppp_generic and connect may take time, plus we may - * race with irnet_connect_indication(), we need to be careful there... */ - if(test_and_set_bit(0, &self->ttp_connect)) - DRETURN(-EBUSY, IRDA_SOCK_INFO, "Already connecting...\n"); - if((self->iriap != NULL) || (self->tsap != NULL)) - DERROR(IRDA_SOCK_ERROR, "Socket not cleaned up...\n"); - - /* Insert ourselves in the hashbin so that the IrNET server can find us. - * Notes : 4th arg is string of 32 char max and must be null terminated - * When 4th arg is used (string), 3rd arg isn't (int) - * Can't re-insert (MUST remove first) so check for that... */ - if((irnet_server.running) && (self->q.q_next == NULL)) - { - spin_lock_bh(&irnet_server.spinlock); - hashbin_insert(irnet_server.list, (irda_queue_t *) self, 0, self->rname); - spin_unlock_bh(&irnet_server.spinlock); - DEBUG(IRDA_SOCK_INFO, "Inserted ``%s'' in hashbin...\n", self->rname); - } - - /* If we don't have anything (no address, no name) */ - if((self->rdaddr == DEV_ADDR_ANY) && (self->rname[0] == '\0')) - { - /* Try to find a suitable address */ - if((err = irnet_discover_daddr_and_lsap_sel(self)) != 0) - DRETURN(err, IRDA_SOCK_INFO, "auto-connect failed!\n"); - /* In most cases, the call above is non-blocking */ - } - else - { - /* If we have only the name (no address), try to get an address */ - if(self->rdaddr == DEV_ADDR_ANY) - { - if((err = irnet_dname_to_daddr(self)) != 0) - DRETURN(err, IRDA_SOCK_INFO, "name connect failed!\n"); - } - else - /* Use the requested destination address */ - self->daddr = self->rdaddr; - - /* Query remote LM-IAS to find LSAP selector */ - irnet_find_lsap_sel(self); - /* The above call is non blocking */ - } - - /* At this point, we are waiting for the IrDA stack to call us back, - * or we have already failed. - * We will finish the connection procedure in irnet_connect_tsap(). - */ - DEXIT(IRDA_SOCK_TRACE, "\n"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_irnet_destroy(self) - * - * Destroy irnet instance - * - * Note : this need to be called from a process context. - */ -void -irda_irnet_destroy(irnet_socket * self) -{ - DENTER(IRDA_SOCK_TRACE, "(self=0x%p)\n", self); - if(self == NULL) - return; - - /* Remove ourselves from hashbin (if we are queued in hashbin) - * Note : `irnet_server.running' protect us from calls in hashbin_delete() */ - if((irnet_server.running) && (self->q.q_next != NULL)) - { - struct irnet_socket * entry; - DEBUG(IRDA_SOCK_INFO, "Removing from hash..\n"); - spin_lock_bh(&irnet_server.spinlock); - entry = hashbin_remove_this(irnet_server.list, (irda_queue_t *) self); - self->q.q_next = NULL; - spin_unlock_bh(&irnet_server.spinlock); - DASSERT(entry == self, , IRDA_SOCK_ERROR, "Can't remove from hash.\n"); - } - - /* If we were connected, post a message */ - if(test_bit(0, &self->ttp_open)) - { - /* Note : as the disconnect comes from ppp_generic, the unit number - * doesn't exist anymore when we post the event, so we need to pass - * NULL as the first arg... */ - irnet_post_event(NULL, IRNET_DISCONNECT_TO, - self->saddr, self->daddr, self->rname, 0); - } - - /* Prevent various IrDA callbacks from messing up things - * Need to be first */ - clear_bit(0, &self->ttp_connect); - - /* Prevent higher layer from accessing IrTTP */ - clear_bit(0, &self->ttp_open); - - /* Unregister with IrLMP */ - irlmp_unregister_client(self->ckey); - - /* Unregister with LM-IAS */ - if(self->iriap) - { - iriap_close(self->iriap); - self->iriap = NULL; - } - - /* Cleanup eventual discoveries from connection attempt or control channel */ - if(self->discoveries != NULL) - { - /* Cleanup our copy of the discovery log */ - kfree(self->discoveries); - self->discoveries = NULL; - } - - /* Close our IrTTP connection */ - if(self->tsap) - { - DEBUG(IRDA_SOCK_INFO, "Closing our TTP connection.\n"); - irttp_disconnect_request(self->tsap, NULL, P_NORMAL); - irttp_close_tsap(self->tsap); - self->tsap = NULL; - } - self->stsap_sel = 0; - - DEXIT(IRDA_SOCK_TRACE, "\n"); -} - - -/************************** SERVER SOCKET **************************/ -/* - * The IrNET service is composed of one server socket and a variable - * number of regular IrNET sockets. The server socket is supposed to - * handle incoming connections and redirect them to one IrNET sockets. - * It's a superset of the regular IrNET socket, but has a very distinct - * behaviour... - */ - -/*------------------------------------------------------------------*/ -/* - * Function irnet_daddr_to_dname (self) - * - * Convert an IrDA address to a IrDA nickname - * - * It basically look into the discovery log until there is a match. - */ -static inline int -irnet_daddr_to_dname(irnet_socket * self) -{ - struct irda_device_info *discoveries; /* Copy of the discovery log */ - int number; /* Number of nodes in the log */ - int i; - - DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); - - /* Ask lmp for the current discovery log */ - discoveries = irlmp_get_discoveries(&number, 0xffff, - DISCOVERY_DEFAULT_SLOTS); - /* Check if the we got some results */ - if (discoveries == NULL) - DRETURN(-ENETUNREACH, IRDA_SERV_INFO, "Cachelog empty...\n"); - - /* Now, check all discovered devices (if any) */ - for(i = 0; i < number; i++) - { - /* Does the name match ? */ - if(discoveries[i].daddr == self->daddr) - { - /* Yes !!! Get it.. */ - strlcpy(self->rname, discoveries[i].info, sizeof(self->rname)); - self->rname[sizeof(self->rname) - 1] = '\0'; - DEBUG(IRDA_SERV_INFO, "Device 0x%08x is in fact ``%s''.\n", - self->daddr, self->rname); - kfree(discoveries); - DEXIT(IRDA_SERV_TRACE, "\n"); - return 0; - } - } - /* No luck ! */ - DEXIT(IRDA_SERV_INFO, ": cannot discover device 0x%08x !!!\n", self->daddr); - kfree(discoveries); - return -EADDRNOTAVAIL; -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_find_socket (self) - * - * Find the correct IrNET socket - * - * Look into the list of IrNET sockets and finds one with the right - * properties... - */ -static inline irnet_socket * -irnet_find_socket(irnet_socket * self) -{ - irnet_socket * new = (irnet_socket *) NULL; - int err; - - DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); - - /* Get the addresses of the requester */ - self->daddr = irttp_get_daddr(self->tsap); - self->saddr = irttp_get_saddr(self->tsap); - - /* Try to get the IrDA nickname of the requester */ - err = irnet_daddr_to_dname(self); - - /* Protect access to the instance list */ - spin_lock_bh(&irnet_server.spinlock); - - /* So now, try to get an socket having specifically - * requested that nickname */ - if(err == 0) - { - new = (irnet_socket *) hashbin_find(irnet_server.list, - 0, self->rname); - if(new) - DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches rname ``%s''.\n", - new, new->rname); - } - - /* If no name matches, try to find an socket by the destination address */ - /* It can be either the requested destination address (set via the - * control channel), or the current destination address if the - * socket is in the middle of a connection request */ - if(new == (irnet_socket *) NULL) - { - new = (irnet_socket *) hashbin_get_first(irnet_server.list); - while(new !=(irnet_socket *) NULL) - { - /* Does it have the same address ? */ - if((new->rdaddr == self->daddr) || (new->daddr == self->daddr)) - { - /* Yes !!! Get it.. */ - DEBUG(IRDA_SERV_INFO, "Socket 0x%p matches daddr %#08x.\n", - new, self->daddr); - break; - } - new = (irnet_socket *) hashbin_get_next(irnet_server.list); - } - } - - /* If we don't have any socket, get the first unconnected socket */ - if(new == (irnet_socket *) NULL) - { - new = (irnet_socket *) hashbin_get_first(irnet_server.list); - while(new !=(irnet_socket *) NULL) - { - /* Is it available ? */ - if(!(test_bit(0, &new->ttp_open)) && (new->rdaddr == DEV_ADDR_ANY) && - (new->rname[0] == '\0') && (new->ppp_open)) - { - /* Yes !!! Get it.. */ - DEBUG(IRDA_SERV_INFO, "Socket 0x%p is free.\n", - new); - break; - } - new = (irnet_socket *) hashbin_get_next(irnet_server.list); - } - } - - /* Spin lock end */ - spin_unlock_bh(&irnet_server.spinlock); - - DEXIT(IRDA_SERV_TRACE, " - new = 0x%p\n", new); - return new; -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_connect_socket (self) - * - * Connect an incoming connection to the socket - * - */ -static inline int -irnet_connect_socket(irnet_socket * server, - irnet_socket * new, - struct qos_info * qos, - __u32 max_sdu_size, - __u8 max_header_size) -{ - DENTER(IRDA_SERV_TRACE, "(server=0x%p, new=0x%p)\n", - server, new); - - /* Now attach up the new socket */ - new->tsap = irttp_dup(server->tsap, new); - DABORT(new->tsap == NULL, -1, IRDA_SERV_ERROR, "dup failed!\n"); - - /* Set up all the relevant parameters on the new socket */ - new->stsap_sel = new->tsap->stsap_sel; - new->dtsap_sel = new->tsap->dtsap_sel; - new->saddr = irttp_get_saddr(new->tsap); - new->daddr = irttp_get_daddr(new->tsap); - - new->max_header_size = max_header_size; - new->max_sdu_size_tx = max_sdu_size; - new->max_data_size = max_sdu_size; -#ifdef STREAM_COMPAT - /* If we want to receive "stream sockets" */ - if(max_sdu_size == 0) - new->max_data_size = irttp_get_max_seg_size(new->tsap); -#endif /* STREAM_COMPAT */ - - /* Clean up the original one to keep it in listen state */ - irttp_listen(server->tsap); - - /* Send a connection response on the new socket */ - irttp_connect_response(new->tsap, new->max_sdu_size_rx, NULL); - - /* Allow PPP to send its junk over the new socket... */ - set_bit(0, &new->ttp_open); - - /* Not connecting anymore, and clean up last possible remains - * of connection attempts on the socket */ - clear_bit(0, &new->ttp_connect); - if(new->iriap) - { - iriap_close(new->iriap); - new->iriap = NULL; - } - if(new->discoveries != NULL) - { - kfree(new->discoveries); - new->discoveries = NULL; - } - -#ifdef CONNECT_INDIC_KICK - /* As currently we don't block packets in ppp_irnet_send() while passive, - * this is not really needed... - * Also, not doing it give IrDA a chance to finish the setup properly - * before being swamped with packets... */ - ppp_output_wakeup(&new->chan); -#endif /* CONNECT_INDIC_KICK */ - - /* Notify the control channel */ - irnet_post_event(new, IRNET_CONNECT_FROM, - new->saddr, new->daddr, server->rname, 0); - - DEXIT(IRDA_SERV_TRACE, "\n"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_disconnect_server (self) - * - * Cleanup the server socket when the incoming connection abort - * - */ -static inline void -irnet_disconnect_server(irnet_socket * self, - struct sk_buff *skb) -{ - DENTER(IRDA_SERV_TRACE, "(self=0x%p)\n", self); - - /* Put the received packet in the black hole */ - kfree_skb(skb); - -#ifdef FAIL_SEND_DISCONNECT - /* Tell the other party we don't want to be connected */ - /* Hum... Is it the right thing to do ? And do we need to send - * a connect response before ? It looks ok without this... */ - irttp_disconnect_request(self->tsap, NULL, P_NORMAL); -#endif /* FAIL_SEND_DISCONNECT */ - - /* Notify the control channel (see irnet_find_socket()) */ - irnet_post_event(NULL, IRNET_REQUEST_FROM, - self->saddr, self->daddr, self->rname, 0); - - /* Clean up the server to keep it in listen state */ - irttp_listen(self->tsap); - - DEXIT(IRDA_SERV_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_setup_server (self) - * - * Create a IrTTP server and set it up... - * - * Register the IrLAN hint bit, create a IrTTP instance for us, - * set all the IrTTP callbacks and create an IrIAS entry... - */ -static inline int -irnet_setup_server(void) -{ - __u16 hints; - - DENTER(IRDA_SERV_TRACE, "()\n"); - - /* Initialise the regular socket part of the server */ - irda_irnet_create(&irnet_server.s); - - /* Open a local TSAP (an IrTTP instance) for the server */ - irnet_open_tsap(&irnet_server.s); - - /* PPP part setup */ - irnet_server.s.ppp_open = 0; - irnet_server.s.chan.private = NULL; - irnet_server.s.file = NULL; - - /* Get the hint bit corresponding to IrLAN */ - /* Note : we overload the IrLAN hint bit. As it is only a "hint", and as - * we provide roughly the same functionality as IrLAN, this is ok. - * In fact, the situation is similar as JetSend overloading the Obex hint - */ - hints = irlmp_service_to_hint(S_LAN); - -#ifdef ADVERTISE_HINT - /* Register with IrLMP as a service (advertise our hint bit) */ - irnet_server.skey = irlmp_register_service(hints); -#endif /* ADVERTISE_HINT */ - - /* Register with LM-IAS (so that people can connect to us) */ - irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies); - irias_add_integer_attrib(irnet_server.ias_obj, IRNET_IAS_VALUE, - irnet_server.s.stsap_sel, IAS_KERNEL_ATTR); - irias_insert_object(irnet_server.ias_obj); - -#ifdef DISCOVERY_EVENTS - /* Tell IrLMP we want to be notified of newly discovered nodes */ - irlmp_update_client(irnet_server.s.ckey, hints, - irnet_discovery_indication, irnet_expiry_indication, - (void *) &irnet_server.s); -#endif - - DEXIT(IRDA_SERV_TRACE, " - self=0x%p\n", &irnet_server.s); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_destroy_server (self) - * - * Destroy the IrTTP server... - * - * Reverse of the previous function... - */ -static inline void -irnet_destroy_server(void) -{ - DENTER(IRDA_SERV_TRACE, "()\n"); - -#ifdef ADVERTISE_HINT - /* Unregister with IrLMP */ - irlmp_unregister_service(irnet_server.skey); -#endif /* ADVERTISE_HINT */ - - /* Unregister with LM-IAS */ - if(irnet_server.ias_obj) - irias_delete_object(irnet_server.ias_obj); - - /* Cleanup the socket part */ - irda_irnet_destroy(&irnet_server.s); - - DEXIT(IRDA_SERV_TRACE, "\n"); -} - - -/************************ IRDA-TTP CALLBACKS ************************/ -/* - * When we create a IrTTP instance, we pass to it a set of callbacks - * that IrTTP will call in case of various events. - * We take care of those events here. - */ - -/*------------------------------------------------------------------*/ -/* - * Function irnet_data_indication (instance, sap, skb) - * - * Received some data from TinyTP. Just queue it on the receive queue - * - */ -static int -irnet_data_indication(void * instance, - void * sap, - struct sk_buff *skb) -{ - irnet_socket * ap = (irnet_socket *) instance; - unsigned char * p; - int code = 0; - - DENTER(IRDA_TCB_TRACE, "(self/ap=0x%p, skb=0x%p)\n", - ap, skb); - DASSERT(skb != NULL, 0, IRDA_CB_ERROR, "skb is NULL !!!\n"); - - /* Check is ppp is ready to receive our packet */ - if(!ap->ppp_open) - { - DERROR(IRDA_CB_ERROR, "PPP not ready, dropping packet...\n"); - /* When we return error, TTP will need to requeue the skb and - * will stop the sender. IrTTP will stall until we send it a - * flow control request... */ - return -ENOMEM; - } - - /* strip address/control field if present */ - p = skb->data; - if((p[0] == PPP_ALLSTATIONS) && (p[1] == PPP_UI)) - { - /* chop off address/control */ - if(skb->len < 3) - goto err_exit; - p = skb_pull(skb, 2); - } - - /* decompress protocol field if compressed */ - if(p[0] & 1) - { - /* protocol is compressed */ - *(u8 *)skb_push(skb, 1) = 0; - } - else - if(skb->len < 2) - goto err_exit; - - /* pass to generic ppp layer */ - /* Note : how do I know if ppp can accept or not the packet ? This is - * essential if I want to manage flow control smoothly... */ - ppp_input(&ap->chan, skb); - - DEXIT(IRDA_TCB_TRACE, "\n"); - return 0; - - err_exit: - DERROR(IRDA_CB_ERROR, "Packet too small, dropping...\n"); - kfree_skb(skb); - ppp_input_error(&ap->chan, code); - return 0; /* Don't return an error code, only for flow control... */ -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_disconnect_indication (instance, sap, reason, skb) - * - * Connection has been closed. Chech reason to find out why - * - * Note : there are many cases where we come here : - * o attempted to connect, timeout - * o connected, link is broken, LAP has timeout - * o connected, other side close the link - * o connection request on the server not handled - */ -static void -irnet_disconnect_indication(void * instance, - void * sap, - LM_REASON reason, - struct sk_buff *skb) -{ - irnet_socket * self = (irnet_socket *) instance; - int test_open; - int test_connect; - - DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); - DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); - - /* Don't care about it, but let's not leak it */ - if(skb) - dev_kfree_skb(skb); - - /* Prevent higher layer from accessing IrTTP */ - test_open = test_and_clear_bit(0, &self->ttp_open); - /* Not connecting anymore... - * (note : TSAP is open, so IAP callbacks are no longer pending...) */ - test_connect = test_and_clear_bit(0, &self->ttp_connect); - - /* If both self->ttp_open and self->ttp_connect are NULL, it mean that we - * have a race condition with irda_irnet_destroy() or - * irnet_connect_indication(), so don't mess up tsap... - */ - if(!(test_open || test_connect)) - { - DERROR(IRDA_CB_ERROR, "Race condition detected...\n"); - return; - } - - /* If we were active, notify the control channel */ - if(test_open) - irnet_post_event(self, IRNET_DISCONNECT_FROM, - self->saddr, self->daddr, self->rname, 0); - else - /* If we were trying to connect, notify the control channel */ - if((self->tsap) && (self != &irnet_server.s)) - irnet_post_event(self, IRNET_NOANSWER_FROM, - self->saddr, self->daddr, self->rname, 0); - - /* Close our IrTTP connection, cleanup tsap */ - if((self->tsap) && (self != &irnet_server.s)) - { - DEBUG(IRDA_CB_INFO, "Closing our TTP connection.\n"); - irttp_close_tsap(self->tsap); - self->tsap = NULL; - } - /* Cleanup the socket in case we want to reconnect in ppp_output_wakeup() */ - self->stsap_sel = 0; - self->daddr = DEV_ADDR_ANY; - self->tx_flow = FLOW_START; - - /* Deal with the ppp instance if it's still alive */ - if(self->ppp_open) - { - if(test_open) - { - /* ppp_unregister_channel() wants a user context. */ - schedule_work(&self->disconnect_work); - } - else - { - /* If we were trying to connect, flush (drain) ppp_generic - * Tx queue (most often we have blocked it), which will - * trigger an other attempt to connect. If we are passive, - * this will empty the Tx queue after last try. */ - ppp_output_wakeup(&self->chan); - } - } - - DEXIT(IRDA_TCB_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_connect_confirm (instance, sap, qos, max_sdu_size, skb) - * - * Connections has been confirmed by the remote device - * - */ -static void -irnet_connect_confirm(void * instance, - void * sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - irnet_socket * self = (irnet_socket *) instance; - - DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); - - /* Check if socket is closing down (via irda_irnet_destroy()) */ - if(! test_bit(0, &self->ttp_connect)) - { - DERROR(IRDA_CB_ERROR, "Socket no longer connecting. Ouch !\n"); - return; - } - - /* How much header space do we need to reserve */ - self->max_header_size = max_header_size; - - /* IrTTP max SDU size in transmit direction */ - self->max_sdu_size_tx = max_sdu_size; - self->max_data_size = max_sdu_size; -#ifdef STREAM_COMPAT - if(max_sdu_size == 0) - self->max_data_size = irttp_get_max_seg_size(self->tsap); -#endif /* STREAM_COMPAT */ - - /* At this point, IrLMP has assigned our source address */ - self->saddr = irttp_get_saddr(self->tsap); - - /* Allow higher layer to access IrTTP */ - set_bit(0, &self->ttp_open); - clear_bit(0, &self->ttp_connect); /* Not racy, IrDA traffic is serial */ - /* Give a kick in the ass of ppp_generic so that he sends us some data */ - ppp_output_wakeup(&self->chan); - - /* Check size of received packet */ - if(skb->len > 0) - { -#ifdef PASS_CONNECT_PACKETS - DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); - /* Try to pass it to PPP */ - irnet_data_indication(instance, sap, skb); -#else /* PASS_CONNECT_PACKETS */ - DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); - kfree_skb(skb); /* Note : will be optimised with other kfree... */ -#endif /* PASS_CONNECT_PACKETS */ - } - else - kfree_skb(skb); - - /* Notify the control channel */ - irnet_post_event(self, IRNET_CONNECT_TO, - self->saddr, self->daddr, self->rname, 0); - - DEXIT(IRDA_TCB_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_flow_indication (instance, sap, flow) - * - * Used by TinyTP to tell us if it can accept more data or not - * - */ -static void -irnet_flow_indication(void * instance, - void * sap, - LOCAL_FLOW flow) -{ - irnet_socket * self = (irnet_socket *) instance; - LOCAL_FLOW oldflow = self->tx_flow; - - DENTER(IRDA_TCB_TRACE, "(self=0x%p, flow=%d)\n", self, flow); - - /* Update our state */ - self->tx_flow = flow; - - /* Check what IrTTP want us to do... */ - switch(flow) - { - case FLOW_START: - DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n"); - /* Check if we really need to wake up PPP */ - if(oldflow == FLOW_STOP) - ppp_output_wakeup(&self->chan); - else - DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n"); - break; - case FLOW_STOP: - DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n"); - break; - default: - DEBUG(IRDA_CB_INFO, "Unknown flow command!\n"); - break; - } - - DEXIT(IRDA_TCB_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_status_indication (instance, sap, reason, skb) - * - * Link (IrLAP) status report. - * - */ -static void -irnet_status_indication(void * instance, - LINK_STATUS link, - LOCK_STATUS lock) -{ - irnet_socket * self = (irnet_socket *) instance; - - DENTER(IRDA_TCB_TRACE, "(self=0x%p)\n", self); - DASSERT(self != NULL, , IRDA_CB_ERROR, "Self is NULL !!!\n"); - - /* We can only get this event if we are connected */ - switch(link) - { - case STATUS_NO_ACTIVITY: - irnet_post_event(self, IRNET_BLOCKED_LINK, - self->saddr, self->daddr, self->rname, 0); - break; - default: - DEBUG(IRDA_CB_INFO, "Unknown status...\n"); - } - - DEXIT(IRDA_TCB_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_connect_indication(instance, sap, qos, max_sdu_size, userdata) - * - * Incoming connection - * - * In theory, this function is called only on the server socket. - * Some other node is attempting to connect to the IrNET service, and has - * sent a connection request on our server socket. - * We just redirect the connection to the relevant IrNET socket. - * - * Note : we also make sure that between 2 irnet nodes, there can - * exist only one irnet connection. - */ -static void -irnet_connect_indication(void * instance, - void * sap, - struct qos_info *qos, - __u32 max_sdu_size, - __u8 max_header_size, - struct sk_buff *skb) -{ - irnet_socket * server = &irnet_server.s; - irnet_socket * new = (irnet_socket *) NULL; - - DENTER(IRDA_TCB_TRACE, "(server=0x%p)\n", server); - DASSERT(instance == &irnet_server, , IRDA_CB_ERROR, - "Invalid instance (0x%p) !!!\n", instance); - DASSERT(sap == irnet_server.s.tsap, , IRDA_CB_ERROR, "Invalid sap !!!\n"); - - /* Try to find the most appropriate IrNET socket */ - new = irnet_find_socket(server); - - /* After all this hard work, do we have an socket ? */ - if(new == (irnet_socket *) NULL) - { - DEXIT(IRDA_CB_INFO, ": No socket waiting for this connection.\n"); - irnet_disconnect_server(server, skb); - return; - } - - /* Is the socket already busy ? */ - if(test_bit(0, &new->ttp_open)) - { - DEXIT(IRDA_CB_INFO, ": Socket already connected.\n"); - irnet_disconnect_server(server, skb); - return; - } - - /* The following code is a bit tricky, so need comments ;-) - */ - /* If ttp_connect is set, the socket is trying to connect to the other - * end and may have sent a IrTTP connection request and is waiting for - * a connection response (that may never come). - * Now, the pain is that the socket may have opened a tsap and is - * waiting on it, while the other end is trying to connect to it on - * another tsap. - * Because IrNET can be peer to peer, we need to workaround this. - * Furthermore, the way the irnetd script is implemented, the - * target will create a second IrNET connection back to the - * originator and expect the originator to bind this new connection - * to the original PPPD instance. - * And of course, if we don't use irnetd, we can have a race when - * both side try to connect simultaneously, which could leave both - * connections half closed (yuck). - * Conclusions : - * 1) The "originator" must accept the new connection and get rid - * of the old one so that irnetd works - * 2) One side must deny the new connection to avoid races, - * but both side must agree on which side it is... - * Most often, the originator is primary at the LAP layer. - * Jean II - */ - /* Now, let's look at the way I wrote the test... - * We need to clear up the ttp_connect flag atomically to prevent - * irnet_disconnect_indication() to mess up the tsap we are going to close. - * We want to clear the ttp_connect flag only if we close the tsap, - * otherwise we will never close it, so we need to check for primary - * *before* doing the test on the flag. - * And of course, ALLOW_SIMULT_CONNECT can disable this entirely... - * Jean II - */ - - /* Socket already connecting ? On primary ? */ - if(0 -#ifdef ALLOW_SIMULT_CONNECT - || ((irttp_is_primary(server->tsap) == 1) && /* primary */ - (test_and_clear_bit(0, &new->ttp_connect))) -#endif /* ALLOW_SIMULT_CONNECT */ - ) - { - DERROR(IRDA_CB_ERROR, "Socket already connecting, but going to reuse it !\n"); - - /* Cleanup the old TSAP if necessary - IrIAP will be cleaned up later */ - if(new->tsap != NULL) - { - /* Close the old connection the new socket was attempting, - * so that we can hook it up to the new connection. - * It's now safe to do it... */ - irttp_close_tsap(new->tsap); - new->tsap = NULL; - } - } - else - { - /* Three options : - * 1) socket was not connecting or connected : ttp_connect should be 0. - * 2) we don't want to connect the socket because we are secondary or - * ALLOW_SIMULT_CONNECT is undefined. ttp_connect should be 1. - * 3) we are half way in irnet_disconnect_indication(), and it's a - * nice race condition... Fortunately, we can detect that by checking - * if tsap is still alive. On the other hand, we can't be in - * irda_irnet_destroy() otherwise we would not have found this - * socket in the hashbin. - * Jean II */ - if((test_bit(0, &new->ttp_connect)) || (new->tsap != NULL)) - { - /* Don't mess this socket, somebody else in in charge... */ - DERROR(IRDA_CB_ERROR, "Race condition detected, socket in use, abort connect...\n"); - irnet_disconnect_server(server, skb); - return; - } - } - - /* So : at this point, we have a socket, and it is idle. Good ! */ - irnet_connect_socket(server, new, qos, max_sdu_size, max_header_size); - - /* Check size of received packet */ - if(skb->len > 0) - { -#ifdef PASS_CONNECT_PACKETS - DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n"); - /* Try to pass it to PPP */ - irnet_data_indication(new, new->tsap, skb); -#else /* PASS_CONNECT_PACKETS */ - DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n"); - kfree_skb(skb); /* Note : will be optimised with other kfree... */ -#endif /* PASS_CONNECT_PACKETS */ - } - else - kfree_skb(skb); - - DEXIT(IRDA_TCB_TRACE, "\n"); -} - - -/********************** IRDA-IAS/LMP CALLBACKS **********************/ -/* - * These are the callbacks called by other layers of the IrDA stack, - * mainly LMP for discovery and IAS for name queries. - */ - -/*------------------------------------------------------------------*/ -/* - * Function irnet_getvalue_confirm (result, obj_id, value, priv) - * - * Got answer from remote LM-IAS, just connect - * - * This is the reply to a IAS query we were doing to find the TSAP of - * the device we want to connect to. - * If we have found a valid TSAP, just initiate the TTP connection - * on this TSAP. - */ -static void -irnet_getvalue_confirm(int result, - __u16 obj_id, - struct ias_value *value, - void * priv) -{ - irnet_socket * self = (irnet_socket *) priv; - - DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); - DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); - - /* Check if already connected (via irnet_connect_socket()) - * or socket is closing down (via irda_irnet_destroy()) */ - if(! test_bit(0, &self->ttp_connect)) - { - DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); - return; - } - - /* We probably don't need to make any more queries */ - iriap_close(self->iriap); - self->iriap = NULL; - - /* Post process the IAS reply */ - self->dtsap_sel = irnet_ias_to_tsap(self, result, value); - - /* If error, just go out */ - if(self->errno) - { - clear_bit(0, &self->ttp_connect); - DERROR(IRDA_OCB_ERROR, "IAS connect failed ! (0x%X)\n", self->errno); - return; - } - - DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", - self->daddr, self->dtsap_sel); - - /* Start up TTP - non blocking */ - irnet_connect_tsap(self); - - DEXIT(IRDA_OCB_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_discovervalue_confirm (result, obj_id, value, priv) - * - * Handle the TSAP discovery procedure state machine. - * Got answer from remote LM-IAS, try next device - * - * We are doing a TSAP discovery procedure, and we got an answer to - * a IAS query we were doing to find the TSAP on one of the address - * in the discovery log. - * - * If we have found a valid TSAP for the first time, save it. If it's - * not the first time we found one, complain. - * - * If we have more addresses in the log, just initiate a new query. - * Note that those query may fail (see irnet_discover_daddr_and_lsap_sel()) - * - * Otherwise, wrap up the procedure (cleanup), check if we have found - * any device and connect to it. - */ -static void -irnet_discovervalue_confirm(int result, - __u16 obj_id, - struct ias_value *value, - void * priv) -{ - irnet_socket * self = (irnet_socket *) priv; - __u8 dtsap_sel; /* TSAP we are looking for */ - - DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); - DASSERT(self != NULL, , IRDA_OCB_ERROR, "Self is NULL !!!\n"); - - /* Check if already connected (via irnet_connect_socket()) - * or socket is closing down (via irda_irnet_destroy()) */ - if(! test_bit(0, &self->ttp_connect)) - { - DERROR(IRDA_OCB_ERROR, "Socket no longer connecting. Ouch !\n"); - return; - } - - /* Post process the IAS reply */ - dtsap_sel = irnet_ias_to_tsap(self, result, value); - - /* Have we got something ? */ - if(self->errno == 0) - { - /* We found the requested service */ - if(self->daddr != DEV_ADDR_ANY) - { - DERROR(IRDA_OCB_ERROR, "More than one device in range supports IrNET...\n"); - } - else - { - /* First time we found that one, save it ! */ - self->daddr = self->discoveries[self->disco_index].daddr; - self->dtsap_sel = dtsap_sel; - } - } - - /* If no failure */ - if((self->errno == -EADDRNOTAVAIL) || (self->errno == 0)) - { - int ret; - - /* Search the next node */ - ret = irnet_discover_next_daddr(self); - if(!ret) - { - /* In this case, the above request was non-blocking. - * We will return here after a while... */ - return; - } - /* In this case, we have processed the last discovery item */ - } - - /* No more queries to be done (failure or last one) */ - - /* We probably don't need to make any more queries */ - iriap_close(self->iriap); - self->iriap = NULL; - - /* No more items : remove the log and signal termination */ - DEBUG(IRDA_OCB_INFO, "Cleaning up log (0x%p)\n", - self->discoveries); - if(self->discoveries != NULL) - { - /* Cleanup our copy of the discovery log */ - kfree(self->discoveries); - self->discoveries = NULL; - } - self->disco_number = -1; - - /* Check out what we found */ - if(self->daddr == DEV_ADDR_ANY) - { - self->daddr = DEV_ADDR_ANY; - clear_bit(0, &self->ttp_connect); - DEXIT(IRDA_OCB_TRACE, ": cannot discover IrNET in any device !!!\n"); - return; - } - - /* We have a valid address - just connect */ - - DEBUG(IRDA_OCB_INFO, "daddr = %08x, lsap = %d, starting IrTTP connection\n", - self->daddr, self->dtsap_sel); - - /* Start up TTP - non blocking */ - irnet_connect_tsap(self); - - DEXIT(IRDA_OCB_TRACE, "\n"); -} - -#ifdef DISCOVERY_EVENTS -/*------------------------------------------------------------------*/ -/* - * Function irnet_discovery_indication (discovery) - * - * Got a discovery indication from IrLMP, post an event - * - * Note : IrLMP take care of matching the hint mask for us, and also - * check if it is a "new" node for us... - * - * As IrLMP filter on the IrLAN hint bit, we get both IrLAN and IrNET - * nodes, so it's only at connection time that we will know if the - * node support IrNET, IrLAN or both. The other solution is to check - * in IAS the PNP ids and service name. - * Note : even if a node support IrNET (or IrLAN), it's no guarantee - * that we will be able to connect to it, the node might already be - * busy... - * - * One last thing : in some case, this function will trigger duplicate - * discovery events. On the other hand, we should catch all - * discoveries properly (i.e. not miss one). Filtering duplicate here - * is to messy, so we leave that to user space... - */ -static void -irnet_discovery_indication(discinfo_t * discovery, - DISCOVERY_MODE mode, - void * priv) -{ - irnet_socket * self = &irnet_server.s; - - DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); - DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, - "Invalid instance (0x%p) !!!\n", priv); - - DEBUG(IRDA_OCB_INFO, "Discovered new IrNET/IrLAN node %s...\n", - discovery->info); - - /* Notify the control channel */ - irnet_post_event(NULL, IRNET_DISCOVER, - discovery->saddr, discovery->daddr, discovery->info, - get_unaligned((__u16 *)discovery->hints)); - - DEXIT(IRDA_OCB_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_expiry_indication (expiry) - * - * Got a expiry indication from IrLMP, post an event - * - * Note : IrLMP take care of matching the hint mask for us, we only - * check if it is a "new" node... - */ -static void -irnet_expiry_indication(discinfo_t * expiry, - DISCOVERY_MODE mode, - void * priv) -{ - irnet_socket * self = &irnet_server.s; - - DENTER(IRDA_OCB_TRACE, "(self=0x%p)\n", self); - DASSERT(priv == &irnet_server, , IRDA_OCB_ERROR, - "Invalid instance (0x%p) !!!\n", priv); - - DEBUG(IRDA_OCB_INFO, "IrNET/IrLAN node %s expired...\n", - expiry->info); - - /* Notify the control channel */ - irnet_post_event(NULL, IRNET_EXPIRE, - expiry->saddr, expiry->daddr, expiry->info, - get_unaligned((__u16 *)expiry->hints)); - - DEXIT(IRDA_OCB_TRACE, "\n"); -} -#endif /* DISCOVERY_EVENTS */ - - -/*********************** PROC ENTRY CALLBACKS ***********************/ -/* - * We create a instance in the /proc filesystem, and here we take care - * of that... - */ - -#ifdef CONFIG_PROC_FS -static int -irnet_proc_show(struct seq_file *m, void *v) -{ - irnet_socket * self; - char * state; - int i = 0; - - /* Get the IrNET server information... */ - seq_printf(m, "IrNET server - "); - seq_printf(m, "IrDA state: %s, ", - (irnet_server.running ? "running" : "dead")); - seq_printf(m, "stsap_sel: %02x, ", irnet_server.s.stsap_sel); - seq_printf(m, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel); - - /* Do we need to continue ? */ - if(!irnet_server.running) - return 0; - - /* Protect access to the instance list */ - spin_lock_bh(&irnet_server.spinlock); - - /* Get the sockets one by one... */ - self = (irnet_socket *) hashbin_get_first(irnet_server.list); - while(self != NULL) - { - /* Start printing info about the socket. */ - seq_printf(m, "\nIrNET socket %d - ", i++); - - /* First, get the requested configuration */ - seq_printf(m, "Requested IrDA name: \"%s\", ", self->rname); - seq_printf(m, "daddr: %08x, ", self->rdaddr); - seq_printf(m, "saddr: %08x\n", self->rsaddr); - - /* Second, get all the PPP info */ - seq_printf(m, " PPP state: %s", - (self->ppp_open ? "registered" : "unregistered")); - if(self->ppp_open) - { - seq_printf(m, ", unit: ppp%d", - ppp_unit_number(&self->chan)); - seq_printf(m, ", channel: %d", - ppp_channel_index(&self->chan)); - seq_printf(m, ", mru: %d", - self->mru); - /* Maybe add self->flags ? Later... */ - } - - /* Then, get all the IrDA specific info... */ - if(self->ttp_open) - state = "connected"; - else - if(self->tsap != NULL) - state = "connecting"; - else - if(self->iriap != NULL) - state = "searching"; - else - if(self->ttp_connect) - state = "weird"; - else - state = "idle"; - seq_printf(m, "\n IrDA state: %s, ", state); - seq_printf(m, "daddr: %08x, ", self->daddr); - seq_printf(m, "stsap_sel: %02x, ", self->stsap_sel); - seq_printf(m, "dtsap_sel: %02x\n", self->dtsap_sel); - - /* Next socket, please... */ - self = (irnet_socket *) hashbin_get_next(irnet_server.list); - } - - /* Spin lock end */ - spin_unlock_bh(&irnet_server.spinlock); - - return 0; -} - -static int irnet_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, irnet_proc_show, NULL); -} - -static const struct file_operations irnet_proc_fops = { - .owner = THIS_MODULE, - .open = irnet_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif /* PROC_FS */ - - -/********************** CONFIGURATION/CLEANUP **********************/ -/* - * Initialisation and teardown of the IrDA part, called at module - * insertion and removal... - */ - -/*------------------------------------------------------------------*/ -/* - * Prepare the IrNET layer for operation... - */ -int __init -irda_irnet_init(void) -{ - int err = 0; - - DENTER(MODULE_TRACE, "()\n"); - - /* Pure paranoia - should be redundant */ - memset(&irnet_server, 0, sizeof(struct irnet_root)); - - /* Setup start of irnet instance list */ - irnet_server.list = hashbin_new(HB_NOLOCK); - DABORT(irnet_server.list == NULL, -ENOMEM, - MODULE_ERROR, "Can't allocate hashbin!\n"); - /* Init spinlock for instance list */ - spin_lock_init(&irnet_server.spinlock); - - /* Initialise control channel */ - init_waitqueue_head(&irnet_events.rwait); - irnet_events.index = 0; - /* Init spinlock for event logging */ - spin_lock_init(&irnet_events.spinlock); - -#ifdef CONFIG_PROC_FS - /* Add a /proc file for irnet infos */ - proc_create("irnet", 0, proc_irda, &irnet_proc_fops); -#endif /* CONFIG_PROC_FS */ - - /* Setup the IrNET server */ - err = irnet_setup_server(); - - if(!err) - /* We are no longer functional... */ - irnet_server.running = 1; - - DEXIT(MODULE_TRACE, "\n"); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Cleanup at exit... - */ -void __exit -irda_irnet_cleanup(void) -{ - DENTER(MODULE_TRACE, "()\n"); - - /* We are no longer there... */ - irnet_server.running = 0; - -#ifdef CONFIG_PROC_FS - /* Remove our /proc file */ - remove_proc_entry("irnet", proc_irda); -#endif /* CONFIG_PROC_FS */ - - /* Remove our IrNET server from existence */ - irnet_destroy_server(); - - /* Remove all instances of IrNET socket still present */ - hashbin_delete(irnet_server.list, (FREE_FUNC) irda_irnet_destroy); - - DEXIT(MODULE_TRACE, "\n"); -} diff --git a/drivers/staging/irda/net/irnet/irnet_irda.h b/drivers/staging/irda/net/irnet/irnet_irda.h deleted file mode 100644 index 3e408952a3f1..000000000000 --- a/drivers/staging/irda/net/irnet/irnet_irda.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * IrNET protocol module : Synchronous PPP over an IrDA socket. - * - * Jean II - HPL `00 - <jt@hpl.hp.com> - * - * This file contains all definitions and declarations necessary for the - * IRDA part of the IrNET module (dealing with IrTTP, IrIAS and co). - * This file is a private header, so other modules don't want to know - * what's in there... - */ - -#ifndef IRNET_IRDA_H -#define IRNET_IRDA_H - -/***************************** INCLUDES *****************************/ -/* Please add other headers in irnet.h */ - -#include "irnet.h" /* Module global include */ - -/************************ CONSTANTS & MACROS ************************/ - -/* - * Name of the service (socket name) used by IrNET - */ -/* IAS object name (or part of it) */ -#define IRNET_SERVICE_NAME "IrNetv1" -/* IAS attribute */ -#define IRNET_IAS_VALUE "IrDA:TinyTP:LsapSel" -/* LMP notify name for client (only for /proc/net/irda/irlmp) */ -#define IRNET_NOTIFY_NAME "IrNET socket" -/* LMP notify name for server (only for /proc/net/irda/irlmp) */ -#define IRNET_NOTIFY_NAME_SERV "IrNET server" - -/****************************** TYPES ******************************/ - -/* - * This is the main structure where we store all the data pertaining to - * the IrNET server (listen for connection requests) and the root - * of the IrNET socket list - */ -typedef struct irnet_root -{ - irnet_socket s; /* To pretend we are a client... */ - - /* Generic stuff */ - int magic; /* Paranoia */ - int running; /* Are we operational ? */ - - /* Link list of all IrNET instances opened */ - hashbin_t * list; - spinlock_t spinlock; /* Serialize access to the list */ - /* Note : the way hashbin has been designed is absolutely not - * reentrant, beware... So, we blindly protect all with spinlock */ - - /* Handle for the hint bit advertised in IrLMP */ - void * skey; - - /* Server socket part */ - struct ias_object * ias_obj; /* Our service name + lsap in IAS */ - -} irnet_root; - - -/**************************** PROTOTYPES ****************************/ - -/* ----------------------- CONTROL CHANNEL ----------------------- */ -static void - irnet_post_event(irnet_socket *, - irnet_event, - __u32, - __u32, - char *, - __u16); -/* ----------------------- IRDA SUBROUTINES ----------------------- */ -static inline int - irnet_open_tsap(irnet_socket *); -static inline __u8 - irnet_ias_to_tsap(irnet_socket *, - int, - struct ias_value *); -static inline int - irnet_find_lsap_sel(irnet_socket *); -static inline int - irnet_connect_tsap(irnet_socket *); -static inline int - irnet_discover_next_daddr(irnet_socket *); -static inline int - irnet_discover_daddr_and_lsap_sel(irnet_socket *); -static inline int - irnet_dname_to_daddr(irnet_socket *); -/* ------------------------ SERVER SOCKET ------------------------ */ -static inline int - irnet_daddr_to_dname(irnet_socket *); -static inline irnet_socket * - irnet_find_socket(irnet_socket *); -static inline int - irnet_connect_socket(irnet_socket *, - irnet_socket *, - struct qos_info *, - __u32, - __u8); -static inline void - irnet_disconnect_server(irnet_socket *, - struct sk_buff *); -static inline int - irnet_setup_server(void); -static inline void - irnet_destroy_server(void); -/* ---------------------- IRDA-TTP CALLBACKS ---------------------- */ -static int - irnet_data_indication(void *, /* instance */ - void *, /* sap */ - struct sk_buff *); -static void - irnet_disconnect_indication(void *, - void *, - LM_REASON, - struct sk_buff *); -static void - irnet_connect_confirm(void *, - void *, - struct qos_info *, - __u32, - __u8, - struct sk_buff *); -static void - irnet_flow_indication(void *, - void *, - LOCAL_FLOW); -static void - irnet_status_indication(void *, - LINK_STATUS, - LOCK_STATUS); -static void - irnet_connect_indication(void *, - void *, - struct qos_info *, - __u32, - __u8, - struct sk_buff *); -/* -------------------- IRDA-IAS/LMP CALLBACKS -------------------- */ -static void - irnet_getvalue_confirm(int, - __u16, - struct ias_value *, - void *); -static void - irnet_discovervalue_confirm(int, - __u16, - struct ias_value *, - void *); -#ifdef DISCOVERY_EVENTS -static void - irnet_discovery_indication(discinfo_t *, - DISCOVERY_MODE, - void *); -static void - irnet_expiry_indication(discinfo_t *, - DISCOVERY_MODE, - void *); -#endif - -/**************************** VARIABLES ****************************/ - -/* - * The IrNET server. Listen to connection requests and co... - */ -static struct irnet_root irnet_server; - -/* Control channel stuff (note : extern) */ -struct irnet_ctrl_channel irnet_events; - -/* The /proc/net/irda directory, defined elsewhere... */ -#ifdef CONFIG_PROC_FS -extern struct proc_dir_entry *proc_irda; -#endif /* CONFIG_PROC_FS */ - -#endif /* IRNET_IRDA_H */ diff --git a/drivers/staging/irda/net/irnet/irnet_ppp.c b/drivers/staging/irda/net/irnet/irnet_ppp.c deleted file mode 100644 index c90a158af4b7..000000000000 --- a/drivers/staging/irda/net/irnet/irnet_ppp.c +++ /dev/null @@ -1,1189 +0,0 @@ -/* - * IrNET protocol module : Synchronous PPP over an IrDA socket. - * - * Jean II - HPL `00 - <jt@hpl.hp.com> - * - * This file implement the PPP interface and /dev/irnet character device. - * The PPP interface hook to the ppp_generic module, handle all our - * relationship to the PPP code in the kernel (and by extension to pppd), - * and exchange PPP frames with this module (send/receive). - * The /dev/irnet device is used primarily for 2 functions : - * 1) as a stub for pppd (the ppp daemon), so that we can appropriately - * generate PPP sessions (we pretend we are a tty). - * 2) as a control channel (write commands, read events) - */ - -#include <linux/sched/signal.h> -#include <linux/slab.h> - -#include "irnet_ppp.h" /* Private header */ -/* Please put other headers in irnet.h - Thanks */ - -/* Generic PPP callbacks (to call us) */ -static const struct ppp_channel_ops irnet_ppp_ops = { - .start_xmit = ppp_irnet_send, - .ioctl = ppp_irnet_ioctl -}; - -/************************* CONTROL CHANNEL *************************/ -/* - * When a pppd instance is not active on /dev/irnet, it acts as a control - * channel. - * Writing allow to set up the IrDA destination of the IrNET channel, - * and any application may be read events happening in IrNET... - */ - -/*------------------------------------------------------------------*/ -/* - * Write is used to send a command to configure a IrNET channel - * before it is open by pppd. The syntax is : "command argument" - * Currently there is only two defined commands : - * o name : set the requested IrDA nickname of the IrNET peer. - * o addr : set the requested IrDA address of the IrNET peer. - * Note : the code is crude, but effective... - */ -static inline ssize_t -irnet_ctrl_write(irnet_socket * ap, - const char __user *buf, - size_t count) -{ - char command[IRNET_MAX_COMMAND]; - char * start; /* Current command being processed */ - char * next; /* Next command to process */ - int length; /* Length of current command */ - - DENTER(CTRL_TRACE, "(ap=0x%p, count=%zd)\n", ap, count); - - /* Check for overflow... */ - DABORT(count >= IRNET_MAX_COMMAND, -ENOMEM, - CTRL_ERROR, "Too much data !!!\n"); - - /* Get the data in the driver */ - if(copy_from_user(command, buf, count)) - { - DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); - return -EFAULT; - } - - /* Safe terminate the string */ - command[count] = '\0'; - DEBUG(CTRL_INFO, "Command line received is ``%s'' (%zd).\n", - command, count); - - /* Check every commands in the command line */ - next = command; - while(next != NULL) - { - /* Look at the next command */ - start = next; - - /* Scrap whitespaces before the command */ - start = skip_spaces(start); - - /* ',' is our command separator */ - next = strchr(start, ','); - if(next) - { - *next = '\0'; /* Terminate command */ - length = next - start; /* Length */ - next++; /* Skip the '\0' */ - } - else - length = strlen(start); - - DEBUG(CTRL_INFO, "Found command ``%s'' (%d).\n", start, length); - - /* Check if we recognised one of the known command - * We can't use "switch" with strings, so hack with "continue" */ - - /* First command : name -> Requested IrDA nickname */ - if(!strncmp(start, "name", 4)) - { - /* Copy the name only if is included and not "any" */ - if((length > 5) && (strcmp(start + 5, "any"))) - { - /* Strip out trailing whitespaces */ - while(isspace(start[length - 1])) - length--; - - DABORT(length < 5 || length > NICKNAME_MAX_LEN + 5, - -EINVAL, CTRL_ERROR, "Invalid nickname.\n"); - - /* Copy the name for later reuse */ - memcpy(ap->rname, start + 5, length - 5); - ap->rname[length - 5] = '\0'; - } - else - ap->rname[0] = '\0'; - DEBUG(CTRL_INFO, "Got rname = ``%s''\n", ap->rname); - - /* Restart the loop */ - continue; - } - - /* Second command : addr, daddr -> Requested IrDA destination address - * Also process : saddr -> Requested IrDA source address */ - if((!strncmp(start, "addr", 4)) || - (!strncmp(start, "daddr", 5)) || - (!strncmp(start, "saddr", 5))) - { - __u32 addr = DEV_ADDR_ANY; - - /* Copy the address only if is included and not "any" */ - if((length > 5) && (strcmp(start + 5, "any"))) - { - char * begp = start + 5; - char * endp; - - /* Scrap whitespaces before the command */ - begp = skip_spaces(begp); - - /* Convert argument to a number (last arg is the base) */ - addr = simple_strtoul(begp, &endp, 16); - /* Has it worked ? (endp should be start + length) */ - DABORT(endp <= (start + 5), -EINVAL, - CTRL_ERROR, "Invalid address.\n"); - } - /* Which type of address ? */ - if(start[0] == 's') - { - /* Save it */ - ap->rsaddr = addr; - DEBUG(CTRL_INFO, "Got rsaddr = %08x\n", ap->rsaddr); - } - else - { - /* Save it */ - ap->rdaddr = addr; - DEBUG(CTRL_INFO, "Got rdaddr = %08x\n", ap->rdaddr); - } - - /* Restart the loop */ - continue; - } - - /* Other possible command : connect N (number of retries) */ - - /* No command matched -> Failed... */ - DABORT(1, -EINVAL, CTRL_ERROR, "Not a recognised IrNET command.\n"); - } - - /* Success : we have parsed all commands successfully */ - return count; -} - -#ifdef INITIAL_DISCOVERY -/*------------------------------------------------------------------*/ -/* - * Function irnet_get_discovery_log (self) - * - * Query the content on the discovery log if not done - * - * This function query the current content of the discovery log - * at the startup of the event channel and save it in the internal struct. - */ -static void -irnet_get_discovery_log(irnet_socket * ap) -{ - __u16 mask = irlmp_service_to_hint(S_LAN); - - /* Ask IrLMP for the current discovery log */ - ap->discoveries = irlmp_get_discoveries(&ap->disco_number, mask, - DISCOVERY_DEFAULT_SLOTS); - - /* Check if the we got some results */ - if(ap->discoveries == NULL) - ap->disco_number = -1; - - DEBUG(CTRL_INFO, "Got the log (0x%p), size is %d\n", - ap->discoveries, ap->disco_number); -} - -/*------------------------------------------------------------------*/ -/* - * Function irnet_read_discovery_log (self, event) - * - * Read the content on the discovery log - * - * This function dump the current content of the discovery log - * at the startup of the event channel. - * Return 1 if wrote an event on the control channel... - * - * State of the ap->disco_XXX variables : - * Socket creation : discoveries = NULL ; disco_index = 0 ; disco_number = 0 - * While reading : discoveries = ptr ; disco_index = X ; disco_number = Y - * After reading : discoveries = NULL ; disco_index = Y ; disco_number = -1 - */ -static inline int -irnet_read_discovery_log(irnet_socket *ap, char *event, int buf_size) -{ - int done_event = 0; - - DENTER(CTRL_TRACE, "(ap=0x%p, event=0x%p)\n", - ap, event); - - /* Test if we have some work to do or we have already finished */ - if(ap->disco_number == -1) - { - DEBUG(CTRL_INFO, "Already done\n"); - return 0; - } - - /* Test if it's the first time and therefore we need to get the log */ - if(ap->discoveries == NULL) - irnet_get_discovery_log(ap); - - /* Check if we have more item to dump */ - if(ap->disco_index < ap->disco_number) - { - /* Write an event */ - snprintf(event, buf_size, - "Found %08x (%s) behind %08x {hints %02X-%02X}\n", - ap->discoveries[ap->disco_index].daddr, - ap->discoveries[ap->disco_index].info, - ap->discoveries[ap->disco_index].saddr, - ap->discoveries[ap->disco_index].hints[0], - ap->discoveries[ap->disco_index].hints[1]); - DEBUG(CTRL_INFO, "Writing discovery %d : %s\n", - ap->disco_index, ap->discoveries[ap->disco_index].info); - - /* We have an event */ - done_event = 1; - /* Next discovery */ - ap->disco_index++; - } - - /* Check if we have done the last item */ - if(ap->disco_index >= ap->disco_number) - { - /* No more items : remove the log and signal termination */ - DEBUG(CTRL_INFO, "Cleaning up log (0x%p)\n", - ap->discoveries); - if(ap->discoveries != NULL) - { - /* Cleanup our copy of the discovery log */ - kfree(ap->discoveries); - ap->discoveries = NULL; - } - ap->disco_number = -1; - } - - return done_event; -} -#endif /* INITIAL_DISCOVERY */ - -/*------------------------------------------------------------------*/ -/* - * Read is used to get IrNET events - */ -static inline ssize_t -irnet_ctrl_read(irnet_socket * ap, - struct file * file, - char __user * buf, - size_t count) -{ - DECLARE_WAITQUEUE(wait, current); - char event[75]; - ssize_t ret = 0; - - DENTER(CTRL_TRACE, "(ap=0x%p, count=%zd)\n", ap, count); - -#ifdef INITIAL_DISCOVERY - /* Check if we have read the log */ - if (irnet_read_discovery_log(ap, event, sizeof(event))) - { - count = min(strlen(event), count); - if (copy_to_user(buf, event, count)) - { - DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); - return -EFAULT; - } - - DEXIT(CTRL_TRACE, "\n"); - return count; - } -#endif /* INITIAL_DISCOVERY */ - - /* Put ourselves on the wait queue to be woken up */ - add_wait_queue(&irnet_events.rwait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - for(;;) - { - /* If there is unread events */ - ret = 0; - if(ap->event_index != irnet_events.index) - break; - ret = -EAGAIN; - if(file->f_flags & O_NONBLOCK) - break; - ret = -ERESTARTSYS; - if(signal_pending(current)) - break; - /* Yield and wait to be woken up */ - schedule(); - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&irnet_events.rwait, &wait); - - /* Did we got it ? */ - if(ret != 0) - { - /* No, return the error code */ - DEXIT(CTRL_TRACE, " - ret %zd\n", ret); - return ret; - } - - /* Which event is it ? */ - switch(irnet_events.log[ap->event_index].event) - { - case IRNET_DISCOVER: - snprintf(event, sizeof(event), - "Discovered %08x (%s) behind %08x {hints %02X-%02X}\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].saddr, - irnet_events.log[ap->event_index].hints.byte[0], - irnet_events.log[ap->event_index].hints.byte[1]); - break; - case IRNET_EXPIRE: - snprintf(event, sizeof(event), - "Expired %08x (%s) behind %08x {hints %02X-%02X}\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].saddr, - irnet_events.log[ap->event_index].hints.byte[0], - irnet_events.log[ap->event_index].hints.byte[1]); - break; - case IRNET_CONNECT_TO: - snprintf(event, sizeof(event), "Connected to %08x (%s) on ppp%d\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].unit); - break; - case IRNET_CONNECT_FROM: - snprintf(event, sizeof(event), "Connection from %08x (%s) on ppp%d\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].unit); - break; - case IRNET_REQUEST_FROM: - snprintf(event, sizeof(event), "Request from %08x (%s) behind %08x\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].saddr); - break; - case IRNET_NOANSWER_FROM: - snprintf(event, sizeof(event), "No-answer from %08x (%s) on ppp%d\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].unit); - break; - case IRNET_BLOCKED_LINK: - snprintf(event, sizeof(event), "Blocked link with %08x (%s) on ppp%d\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].unit); - break; - case IRNET_DISCONNECT_FROM: - snprintf(event, sizeof(event), "Disconnection from %08x (%s) on ppp%d\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name, - irnet_events.log[ap->event_index].unit); - break; - case IRNET_DISCONNECT_TO: - snprintf(event, sizeof(event), "Disconnected to %08x (%s)\n", - irnet_events.log[ap->event_index].daddr, - irnet_events.log[ap->event_index].name); - break; - default: - snprintf(event, sizeof(event), "Bug\n"); - } - /* Increment our event index */ - ap->event_index = (ap->event_index + 1) % IRNET_MAX_EVENTS; - - DEBUG(CTRL_INFO, "Event is :%s", event); - - count = min(strlen(event), count); - if (copy_to_user(buf, event, count)) - { - DERROR(CTRL_ERROR, "Invalid user space pointer.\n"); - return -EFAULT; - } - - DEXIT(CTRL_TRACE, "\n"); - return count; -} - -/*------------------------------------------------------------------*/ -/* - * Poll : called when someone do a select on /dev/irnet. - * Just check if there are new events... - */ -static inline __poll_t -irnet_ctrl_poll(irnet_socket * ap, - struct file * file, - poll_table * wait) -{ - __poll_t mask; - - DENTER(CTRL_TRACE, "(ap=0x%p)\n", ap); - - poll_wait(file, &irnet_events.rwait, wait); - mask = EPOLLOUT | EPOLLWRNORM; - /* If there is unread events */ - if(ap->event_index != irnet_events.index) - mask |= EPOLLIN | EPOLLRDNORM; -#ifdef INITIAL_DISCOVERY - if(ap->disco_number != -1) - { - /* Test if it's the first time and therefore we need to get the log */ - if(ap->discoveries == NULL) - irnet_get_discovery_log(ap); - /* Recheck */ - if(ap->disco_number != -1) - mask |= EPOLLIN | EPOLLRDNORM; - } -#endif /* INITIAL_DISCOVERY */ - - DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask); - return mask; -} - - -/*********************** FILESYSTEM CALLBACKS ***********************/ -/* - * Implement the usual open, read, write functions that will be called - * by the file system when some action is performed on /dev/irnet. - * Most of those actions will in fact be performed by "pppd" or - * the control channel, we just act as a redirector... - */ - -/*------------------------------------------------------------------*/ -/* - * Open : when somebody open /dev/irnet - * We basically create a new instance of irnet and initialise it. - */ -static int -dev_irnet_open(struct inode * inode, - struct file * file) -{ - struct irnet_socket * ap; - int err; - - DENTER(FS_TRACE, "(file=0x%p)\n", file); - -#ifdef SECURE_DEVIRNET - /* This could (should?) be enforced by the permissions on /dev/irnet. */ - if(!capable(CAP_NET_ADMIN)) - return -EPERM; -#endif /* SECURE_DEVIRNET */ - - /* Allocate a private structure for this IrNET instance */ - ap = kzalloc(sizeof(*ap), GFP_KERNEL); - DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n"); - - /* initialize the irnet structure */ - ap->file = file; - - /* PPP channel setup */ - ap->ppp_open = 0; - ap->chan.private = ap; - ap->chan.ops = &irnet_ppp_ops; - ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); - ap->chan.hdrlen = 2 + TTP_MAX_HEADER; /* for A/C + Max IrDA hdr */ - /* PPP parameters */ - ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN); - ap->xaccm[0] = ~0U; - ap->xaccm[3] = 0x60000000U; - ap->raccm = ~0U; - - /* Setup the IrDA part... */ - err = irda_irnet_create(ap); - if(err) - { - DERROR(FS_ERROR, "Can't setup IrDA link...\n"); - kfree(ap); - - return err; - } - - /* For the control channel */ - ap->event_index = irnet_events.index; /* Cancel all past events */ - - mutex_init(&ap->lock); - - /* Put our stuff where we will be able to find it later */ - file->private_data = ap; - - DEXIT(FS_TRACE, " - ap=0x%p\n", ap); - - return 0; -} - - -/*------------------------------------------------------------------*/ -/* - * Close : when somebody close /dev/irnet - * Destroy the instance of /dev/irnet - */ -static int -dev_irnet_close(struct inode * inode, - struct file * file) -{ - irnet_socket * ap = file->private_data; - - DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", - file, ap); - DABORT(ap == NULL, 0, FS_ERROR, "ap is NULL !!!\n"); - - /* Detach ourselves */ - file->private_data = NULL; - - /* Close IrDA stuff */ - irda_irnet_destroy(ap); - - /* Disconnect from the generic PPP layer if not already done */ - if(ap->ppp_open) - { - DERROR(FS_ERROR, "Channel still registered - deregistering !\n"); - ap->ppp_open = 0; - ppp_unregister_channel(&ap->chan); - } - - kfree(ap); - - DEXIT(FS_TRACE, "\n"); - return 0; -} - -/*------------------------------------------------------------------*/ -/* - * Write does nothing. - * (we receive packet from ppp_generic through ppp_irnet_send()) - */ -static ssize_t -dev_irnet_write(struct file * file, - const char __user *buf, - size_t count, - loff_t * ppos) -{ - irnet_socket * ap = file->private_data; - - DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%zd)\n", - file, ap, count); - DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); - - /* If we are connected to ppp_generic, let it handle the job */ - if(ap->ppp_open) - return -EAGAIN; - else - return irnet_ctrl_write(ap, buf, count); -} - -/*------------------------------------------------------------------*/ -/* - * Read doesn't do much either. - * (pppd poll us, but ultimately reads through /dev/ppp) - */ -static ssize_t -dev_irnet_read(struct file * file, - char __user * buf, - size_t count, - loff_t * ppos) -{ - irnet_socket * ap = file->private_data; - - DPASS(FS_TRACE, "(file=0x%p, ap=0x%p, count=%zd)\n", - file, ap, count); - DABORT(ap == NULL, -ENXIO, FS_ERROR, "ap is NULL !!!\n"); - - /* If we are connected to ppp_generic, let it handle the job */ - if(ap->ppp_open) - return -EAGAIN; - else - return irnet_ctrl_read(ap, file, buf, count); -} - -/*------------------------------------------------------------------*/ -/* - * Poll : called when someone do a select on /dev/irnet - */ -static __poll_t -dev_irnet_poll(struct file * file, - poll_table * wait) -{ - irnet_socket * ap = file->private_data; - __poll_t mask; - - DENTER(FS_TRACE, "(file=0x%p, ap=0x%p)\n", - file, ap); - - mask = EPOLLOUT | EPOLLWRNORM; - DABORT(ap == NULL, mask, FS_ERROR, "ap is NULL !!!\n"); - - /* If we are connected to ppp_generic, let it handle the job */ - if(!ap->ppp_open) - mask |= irnet_ctrl_poll(ap, file, wait); - - DEXIT(FS_TRACE, " - mask=0x%X\n", mask); - return mask; -} - -/*------------------------------------------------------------------*/ -/* - * IOCtl : Called when someone does some ioctls on /dev/irnet - * This is the way pppd configure us and control us while the PPP - * instance is active. - */ -static long -dev_irnet_ioctl( - struct file * file, - unsigned int cmd, - unsigned long arg) -{ - irnet_socket * ap = file->private_data; - int err; - int val; - void __user *argp = (void __user *)arg; - - DENTER(FS_TRACE, "(file=0x%p, ap=0x%p, cmd=0x%X)\n", - file, ap, cmd); - - /* Basic checks... */ - DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); -#ifdef SECURE_DEVIRNET - if(!capable(CAP_NET_ADMIN)) - return -EPERM; -#endif /* SECURE_DEVIRNET */ - - err = -EFAULT; - switch(cmd) - { - /* Set discipline (should be N_SYNC_PPP or N_TTY) */ - case TIOCSETD: - if(get_user(val, (int __user *)argp)) - break; - if((val == N_SYNC_PPP) || (val == N_PPP)) - { - DEBUG(FS_INFO, "Entering PPP discipline.\n"); - /* PPP channel setup (ap->chan in configured in dev_irnet_open())*/ - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - - err = ppp_register_channel(&ap->chan); - if(err == 0) - { - /* Our ppp side is active */ - ap->ppp_open = 1; - - DEBUG(FS_INFO, "Trying to establish a connection.\n"); - /* Setup the IrDA link now - may fail... */ - irda_irnet_connect(ap); - } - else - DERROR(FS_ERROR, "Can't setup PPP channel...\n"); - - mutex_unlock(&ap->lock); - } - else - { - /* In theory, should be N_TTY */ - DEBUG(FS_INFO, "Exiting PPP discipline.\n"); - /* Disconnect from the generic PPP layer */ - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - - if(ap->ppp_open) - { - ap->ppp_open = 0; - ppp_unregister_channel(&ap->chan); - } - else - DERROR(FS_ERROR, "Channel not registered !\n"); - err = 0; - - mutex_unlock(&ap->lock); - } - break; - - /* Query PPP channel and unit number */ - case PPPIOCGCHAN: - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - - if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan), - (int __user *)argp)) - err = 0; - - mutex_unlock(&ap->lock); - break; - case PPPIOCGUNIT: - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - - if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan), - (int __user *)argp)) - err = 0; - - mutex_unlock(&ap->lock); - break; - - /* All these ioctls can be passed both directly and from ppp_generic, - * so we just deal with them in one place... - */ - case PPPIOCGFLAGS: - case PPPIOCSFLAGS: - case PPPIOCGASYNCMAP: - case PPPIOCSASYNCMAP: - case PPPIOCGRASYNCMAP: - case PPPIOCSRASYNCMAP: - case PPPIOCGXASYNCMAP: - case PPPIOCSXASYNCMAP: - case PPPIOCGMRU: - case PPPIOCSMRU: - DEBUG(FS_INFO, "Standard PPP ioctl.\n"); - if(!capable(CAP_NET_ADMIN)) - err = -EPERM; - else { - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - - err = ppp_irnet_ioctl(&ap->chan, cmd, arg); - - mutex_unlock(&ap->lock); - } - break; - - /* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */ - /* Get termios */ - case TCGETS: - DEBUG(FS_INFO, "Get termios.\n"); - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - -#ifndef TCGETS2 - if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios)) - err = 0; -#else - if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios)) - err = 0; -#endif - - mutex_unlock(&ap->lock); - break; - /* Set termios */ - case TCSETSF: - DEBUG(FS_INFO, "Set termios.\n"); - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - -#ifndef TCGETS2 - if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp)) - err = 0; -#else - if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp)) - err = 0; -#endif - - mutex_unlock(&ap->lock); - break; - - /* Set DTR/RTS */ - case TIOCMBIS: - case TIOCMBIC: - /* Set exclusive/non-exclusive mode */ - case TIOCEXCL: - case TIOCNXCL: - DEBUG(FS_INFO, "TTY compatibility.\n"); - err = 0; - break; - - case TCGETA: - DEBUG(FS_INFO, "TCGETA\n"); - break; - - case TCFLSH: - DEBUG(FS_INFO, "TCFLSH\n"); - /* Note : this will flush buffers in PPP, so it *must* be done - * We should also worry that we don't accept junk here and that - * we get rid of our own buffers */ -#ifdef FLUSH_TO_PPP - if (mutex_lock_interruptible(&ap->lock)) - return -EINTR; - ppp_output_wakeup(&ap->chan); - mutex_unlock(&ap->lock); -#endif /* FLUSH_TO_PPP */ - err = 0; - break; - - case FIONREAD: - DEBUG(FS_INFO, "FIONREAD\n"); - val = 0; - if(put_user(val, (int __user *)argp)) - break; - err = 0; - break; - - default: - DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd); - err = -ENOTTY; - } - - DEXIT(FS_TRACE, " - err = 0x%X\n", err); - return err; -} - -/************************** PPP CALLBACKS **************************/ -/* - * This are the functions that the generic PPP driver in the kernel - * will call to communicate to us. - */ - -/*------------------------------------------------------------------*/ -/* - * Prepare the ppp frame for transmission over the IrDA socket. - * We make sure that the header space is enough, and we change ppp header - * according to flags passed by pppd. - * This is not a callback, but just a helper function used in ppp_irnet_send() - */ -static inline struct sk_buff * -irnet_prepare_skb(irnet_socket * ap, - struct sk_buff * skb) -{ - unsigned char * data; - int proto; /* PPP protocol */ - int islcp; /* Protocol == LCP */ - int needaddr; /* Need PPP address */ - - DENTER(PPP_TRACE, "(ap=0x%p, skb=0x%p)\n", - ap, skb); - - /* Extract PPP protocol from the frame */ - data = skb->data; - proto = (data[0] << 8) + data[1]; - - /* LCP packets with codes between 1 (configure-request) - * and 7 (code-reject) must be sent as though no options - * have been negotiated. */ - islcp = (proto == PPP_LCP) && (1 <= data[2]) && (data[2] <= 7); - - /* compress protocol field if option enabled */ - if((data[0] == 0) && (ap->flags & SC_COMP_PROT) && (!islcp)) - skb_pull(skb,1); - - /* Check if we need address/control fields */ - needaddr = 2*((ap->flags & SC_COMP_AC) == 0 || islcp); - - /* Is the skb headroom large enough to contain all IrDA-headers? */ - if((skb_headroom(skb) < (ap->max_header_size + needaddr)) || - (skb_shared(skb))) - { - struct sk_buff * new_skb; - - DEBUG(PPP_INFO, "Reallocating skb\n"); - - /* Create a new skb */ - new_skb = skb_realloc_headroom(skb, ap->max_header_size + needaddr); - - /* We have to free the original skb anyway */ - dev_kfree_skb(skb); - - /* Did the realloc succeed ? */ - DABORT(new_skb == NULL, NULL, PPP_ERROR, "Could not realloc skb\n"); - - /* Use the new skb instead */ - skb = new_skb; - } - - /* prepend address/control fields if necessary */ - if(needaddr) - { - skb_push(skb, 2); - skb->data[0] = PPP_ALLSTATIONS; - skb->data[1] = PPP_UI; - } - - DEXIT(PPP_TRACE, "\n"); - - return skb; -} - -/*------------------------------------------------------------------*/ -/* - * Send a packet to the peer over the IrTTP connection. - * Returns 1 iff the packet was accepted. - * Returns 0 iff packet was not consumed. - * If the packet was not accepted, we will call ppp_output_wakeup - * at some later time to reactivate flow control in ppp_generic. - */ -static int -ppp_irnet_send(struct ppp_channel * chan, - struct sk_buff * skb) -{ - irnet_socket * self = (struct irnet_socket *) chan->private; - int ret; - - DENTER(PPP_TRACE, "(channel=0x%p, ap/self=0x%p)\n", - chan, self); - - /* Check if things are somewhat valid... */ - DASSERT(self != NULL, 0, PPP_ERROR, "Self is NULL !!!\n"); - - /* Check if we are connected */ - if(!(test_bit(0, &self->ttp_open))) - { -#ifdef CONNECT_IN_SEND - /* Let's try to connect one more time... */ - /* Note : we won't be connected after this call, but we should be - * ready for next packet... */ - /* If we are already connecting, this will fail */ - irda_irnet_connect(self); -#endif /* CONNECT_IN_SEND */ - - DEBUG(PPP_INFO, "IrTTP not ready ! (%ld-%ld)\n", - self->ttp_open, self->ttp_connect); - - /* Note : we can either drop the packet or block the packet. - * - * Blocking the packet allow us a better connection time, - * because by calling ppp_output_wakeup() we can have - * ppp_generic resending the LCP request immediately to us, - * rather than waiting for one of pppd periodic transmission of - * LCP request. - * - * On the other hand, if we block all packet, all those periodic - * transmissions of pppd accumulate in ppp_generic, creating a - * backlog of LCP request. When we eventually connect later on, - * we have to transmit all this backlog before we can connect - * proper (if we don't timeout before). - * - * The current strategy is as follow : - * While we are attempting to connect, we block packets to get - * a better connection time. - * If we fail to connect, we drain the queue and start dropping packets - */ -#ifdef BLOCK_WHEN_CONNECT - /* If we are attempting to connect */ - if(test_bit(0, &self->ttp_connect)) - { - /* Blocking packet, ppp_generic will retry later */ - return 0; - } -#endif /* BLOCK_WHEN_CONNECT */ - - /* Dropping packet, pppd will retry later */ - dev_kfree_skb(skb); - return 1; - } - - /* Check if the queue can accept any packet, otherwise block */ - if(self->tx_flow != FLOW_START) - DRETURN(0, PPP_INFO, "IrTTP queue full (%d skbs)...\n", - skb_queue_len(&self->tsap->tx_queue)); - - /* Prepare ppp frame for transmission */ - skb = irnet_prepare_skb(self, skb); - DABORT(skb == NULL, 1, PPP_ERROR, "Prepare skb for Tx failed.\n"); - - /* Send the packet to IrTTP */ - ret = irttp_data_request(self->tsap, skb); - if(ret < 0) - { - /* - * > IrTTPs tx queue is full, so we just have to - * > drop the frame! You might think that we should - * > just return -1 and don't deallocate the frame, - * > but that is dangerous since it's possible that - * > we have replaced the original skb with a new - * > one with larger headroom, and that would really - * > confuse do_dev_queue_xmit() in dev.c! I have - * > tried :-) DB - * Correction : we verify the flow control above (self->tx_flow), - * so we come here only if IrTTP doesn't like the packet (empty, - * too large, IrTTP not connected). In those rare cases, it's ok - * to drop it, we don't want to see it here again... - * Jean II - */ - DERROR(PPP_ERROR, "IrTTP doesn't like this packet !!! (0x%X)\n", ret); - /* irttp_data_request already free the packet */ - } - - DEXIT(PPP_TRACE, "\n"); - return 1; /* Packet has been consumed */ -} - -/*------------------------------------------------------------------*/ -/* - * Take care of the ioctls that ppp_generic doesn't want to deal with... - * Note : we are also called from dev_irnet_ioctl(). - */ -static int -ppp_irnet_ioctl(struct ppp_channel * chan, - unsigned int cmd, - unsigned long arg) -{ - irnet_socket * ap = (struct irnet_socket *) chan->private; - int err; - int val; - u32 accm[8]; - void __user *argp = (void __user *)arg; - - DENTER(PPP_TRACE, "(channel=0x%p, ap=0x%p, cmd=0x%X)\n", - chan, ap, cmd); - - /* Basic checks... */ - DASSERT(ap != NULL, -ENXIO, PPP_ERROR, "ap is NULL...\n"); - - err = -EFAULT; - switch(cmd) - { - /* PPP flags */ - case PPPIOCGFLAGS: - val = ap->flags | ap->rbits; - if(put_user(val, (int __user *) argp)) - break; - err = 0; - break; - case PPPIOCSFLAGS: - if(get_user(val, (int __user *) argp)) - break; - ap->flags = val & ~SC_RCV_BITS; - ap->rbits = val & SC_RCV_BITS; - err = 0; - break; - - /* Async map stuff - all dummy to please pppd */ - case PPPIOCGASYNCMAP: - if(put_user(ap->xaccm[0], (u32 __user *) argp)) - break; - err = 0; - break; - case PPPIOCSASYNCMAP: - if(get_user(ap->xaccm[0], (u32 __user *) argp)) - break; - err = 0; - break; - case PPPIOCGRASYNCMAP: - if(put_user(ap->raccm, (u32 __user *) argp)) - break; - err = 0; - break; - case PPPIOCSRASYNCMAP: - if(get_user(ap->raccm, (u32 __user *) argp)) - break; - err = 0; - break; - case PPPIOCGXASYNCMAP: - if(copy_to_user(argp, ap->xaccm, sizeof(ap->xaccm))) - break; - err = 0; - break; - case PPPIOCSXASYNCMAP: - if(copy_from_user(accm, argp, sizeof(accm))) - break; - accm[2] &= ~0x40000000U; /* can't escape 0x5e */ - accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ - memcpy(ap->xaccm, accm, sizeof(ap->xaccm)); - err = 0; - break; - - /* Max PPP frame size */ - case PPPIOCGMRU: - if(put_user(ap->mru, (int __user *) argp)) - break; - err = 0; - break; - case PPPIOCSMRU: - if(get_user(val, (int __user *) argp)) - break; - if(val < PPP_MRU) - val = PPP_MRU; - ap->mru = val; - err = 0; - break; - - default: - DEBUG(PPP_INFO, "Unsupported ioctl (0x%X)\n", cmd); - err = -ENOIOCTLCMD; - } - - DEXIT(PPP_TRACE, " - err = 0x%X\n", err); - return err; -} - -/************************** INITIALISATION **************************/ -/* - * Module initialisation and all that jazz... - */ - -/*------------------------------------------------------------------*/ -/* - * Hook our device callbacks in the filesystem, to connect our code - * to /dev/irnet - */ -static inline int __init -ppp_irnet_init(void) -{ - int err = 0; - - DENTER(MODULE_TRACE, "()\n"); - - /* Allocate ourselves as a minor in the misc range */ - err = misc_register(&irnet_misc_device); - - DEXIT(MODULE_TRACE, "\n"); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Cleanup at exit... - */ -static inline void __exit -ppp_irnet_cleanup(void) -{ - DENTER(MODULE_TRACE, "()\n"); - - /* De-allocate /dev/irnet minor in misc range */ - misc_deregister(&irnet_misc_device); - - DEXIT(MODULE_TRACE, "\n"); -} - -/*------------------------------------------------------------------*/ -/* - * Module main entry point - */ -static int __init -irnet_init(void) -{ - int err; - - /* Initialise both parts... */ - err = irda_irnet_init(); - if(!err) - err = ppp_irnet_init(); - return err; -} - -/*------------------------------------------------------------------*/ -/* - * Module exit - */ -static void __exit -irnet_cleanup(void) -{ - irda_irnet_cleanup(); - ppp_irnet_cleanup(); -} - -/*------------------------------------------------------------------*/ -/* - * Module magic - */ -module_init(irnet_init); -module_exit(irnet_cleanup); -MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); -MODULE_DESCRIPTION("IrNET : Synchronous PPP over IrDA"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV(10, 187); diff --git a/drivers/staging/irda/net/irnet/irnet_ppp.h b/drivers/staging/irda/net/irnet/irnet_ppp.h deleted file mode 100644 index e6d5aa2a8aac..000000000000 --- a/drivers/staging/irda/net/irnet/irnet_ppp.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * IrNET protocol module : Synchronous PPP over an IrDA socket. - * - * Jean II - HPL `00 - <jt@hpl.hp.com> - * - * This file contains all definitions and declarations necessary for the - * PPP part of the IrNET module. - * This file is a private header, so other modules don't want to know - * what's in there... - */ - -#ifndef IRNET_PPP_H -#define IRNET_PPP_H - -/***************************** INCLUDES *****************************/ - -#include "irnet.h" /* Module global include */ -#include <linux/miscdevice.h> - -/************************ CONSTANTS & MACROS ************************/ - -/* IrNET control channel stuff */ -#define IRNET_MAX_COMMAND 256 /* Max length of a command line */ - -/* PPP hardcore stuff */ - -/* Bits in rbits (PPP flags in irnet struct) */ -#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) - -/* Bit numbers in busy */ -#define XMIT_BUSY 0 -#define RECV_BUSY 1 -#define XMIT_WAKEUP 2 -#define XMIT_FULL 3 - -/* Queue management */ -#define PPPSYNC_MAX_RQLEN 32 /* arbitrary */ - -/****************************** TYPES ******************************/ - - -/**************************** PROTOTYPES ****************************/ - -/* ----------------------- CONTROL CHANNEL ----------------------- */ -static inline ssize_t - irnet_ctrl_write(irnet_socket *, - const char *, - size_t); -static inline ssize_t - irnet_ctrl_read(irnet_socket *, - struct file *, - char *, - size_t); -static inline unsigned int - irnet_ctrl_poll(irnet_socket *, - struct file *, - poll_table *); -/* ----------------------- CHARACTER DEVICE ----------------------- */ -static int - dev_irnet_open(struct inode *, /* fs callback : open */ - struct file *), - dev_irnet_close(struct inode *, - struct file *); -static ssize_t - dev_irnet_write(struct file *, - const char __user *, - size_t, - loff_t *), - dev_irnet_read(struct file *, - char __user *, - size_t, - loff_t *); -static __poll_t - dev_irnet_poll(struct file *, - poll_table *); -static long - dev_irnet_ioctl(struct file *, - unsigned int, - unsigned long); -/* ------------------------ PPP INTERFACE ------------------------ */ -static inline struct sk_buff * - irnet_prepare_skb(irnet_socket *, - struct sk_buff *); -static int - ppp_irnet_send(struct ppp_channel *, - struct sk_buff *); -static int - ppp_irnet_ioctl(struct ppp_channel *, - unsigned int, - unsigned long); - -/**************************** VARIABLES ****************************/ - -/* Filesystem callbacks (to call us) */ -static const struct file_operations irnet_device_fops = -{ - .owner = THIS_MODULE, - .read = dev_irnet_read, - .write = dev_irnet_write, - .poll = dev_irnet_poll, - .unlocked_ioctl = dev_irnet_ioctl, - .open = dev_irnet_open, - .release = dev_irnet_close, - .llseek = noop_llseek, - /* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */ -}; - -/* Structure so that the misc major (drivers/char/misc.c) take care of us... */ -static struct miscdevice irnet_misc_device = -{ - .minor = IRNET_MINOR, - .name = "irnet", - .fops = &irnet_device_fops -}; - -#endif /* IRNET_PPP_H */ diff --git a/drivers/staging/irda/net/irnetlink.c b/drivers/staging/irda/net/irnetlink.c deleted file mode 100644 index 7fc340e574cf..000000000000 --- a/drivers/staging/irda/net/irnetlink.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * IrDA netlink layer, for stack configuration. - * - * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org> - * - * Partly based on the 802.11 nelink implementation - * (see net/wireless/nl80211.c) which is: - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * 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 <linux/socket.h> -#include <linux/irda.h> -#include <linux/gfp.h> -#include <net/net_namespace.h> -#include <net/sock.h> -#include <net/irda/irda.h> -#include <net/irda/irlap.h> -#include <net/genetlink.h> - - - -static struct genl_family irda_nl_family; - -static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *info) -{ - char * ifname; - - if (!info->attrs[IRDA_NL_ATTR_IFNAME]) - return NULL; - - ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]); - - pr_debug("%s(): Looking for %s\n", __func__, ifname); - - return dev_get_by_name(net, ifname); -} - -static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) -{ - struct net_device * dev; - struct irlap_cb * irlap; - u32 mode; - - if (!info->attrs[IRDA_NL_ATTR_MODE]) - return -EINVAL; - - mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]); - - pr_debug("%s(): Switching to mode: %d\n", __func__, mode); - - dev = ifname_to_netdev(&init_net, info); - if (!dev) - return -ENODEV; - - irlap = (struct irlap_cb *)dev->atalk_ptr; - if (!irlap) { - dev_put(dev); - return -ENODEV; - } - - irlap->mode = mode; - - dev_put(dev); - - return 0; -} - -static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info) -{ - struct net_device * dev; - struct irlap_cb * irlap; - struct sk_buff *msg; - void *hdr; - int ret = -ENOBUFS; - - dev = ifname_to_netdev(&init_net, info); - if (!dev) - return -ENODEV; - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) { - dev_put(dev); - return -ENOMEM; - } - - irlap = (struct irlap_cb *)dev->atalk_ptr; - if (!irlap) { - ret = -ENODEV; - goto err_out; - } - - hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, - &irda_nl_family, 0, IRDA_NL_CMD_GET_MODE); - if (hdr == NULL) { - ret = -EMSGSIZE; - goto err_out; - } - - if(nla_put_string(msg, IRDA_NL_ATTR_IFNAME, - dev->name)) - goto err_out; - - if(nla_put_u32(msg, IRDA_NL_ATTR_MODE, irlap->mode)) - goto err_out; - - genlmsg_end(msg, hdr); - - return genlmsg_reply(msg, info); - - err_out: - nlmsg_free(msg); - dev_put(dev); - - return ret; -} - -static const struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = { - [IRDA_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING, - .len = IFNAMSIZ-1 }, - [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 }, -}; - -static const struct genl_ops irda_nl_ops[] = { - { - .cmd = IRDA_NL_CMD_SET_MODE, - .doit = irda_nl_set_mode, - .policy = irda_nl_policy, - .flags = GENL_ADMIN_PERM, - }, - { - .cmd = IRDA_NL_CMD_GET_MODE, - .doit = irda_nl_get_mode, - .policy = irda_nl_policy, - /* can be retrieved by unprivileged users */ - }, - -}; - -static struct genl_family irda_nl_family __ro_after_init = { - .name = IRDA_NL_NAME, - .hdrsize = 0, - .version = IRDA_NL_VERSION, - .maxattr = IRDA_NL_CMD_MAX, - .module = THIS_MODULE, - .ops = irda_nl_ops, - .n_ops = ARRAY_SIZE(irda_nl_ops), -}; - -int __init irda_nl_register(void) -{ - return genl_register_family(&irda_nl_family); -} - -void irda_nl_unregister(void) -{ - genl_unregister_family(&irda_nl_family); -} diff --git a/drivers/staging/irda/net/irproc.c b/drivers/staging/irda/net/irproc.c deleted file mode 100644 index 77cfdde9d82f..000000000000 --- a/drivers/staging/irda/net/irproc.c +++ /dev/null @@ -1,96 +0,0 @@ -/********************************************************************* - * - * Filename: irproc.c - * Version: 1.0 - * Description: Various entries in the /proc file system - * Status: Experimental. - * Author: Thomas Davis, <ratbert@radiks.net> - * Created at: Sat Feb 21 21:33:24 1998 - * Modified at: Sun Nov 14 08:54:54 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999, Dag Brattli <dagb@cs.uit.no> - * Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>, - * All Rights Reserved. - * - * 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. - * - * I, Thomas Davis, provide no warranty for any of this software. - * This material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/module.h> -#include <linux/init.h> -#include <net/net_namespace.h> - -#include <net/irda/irda.h> -#include <net/irda/irlap.h> -#include <net/irda/irlmp.h> - -extern const struct file_operations discovery_seq_fops; -extern const struct file_operations irlap_seq_fops; -extern const struct file_operations irlmp_seq_fops; -extern const struct file_operations irttp_seq_fops; -extern const struct file_operations irias_seq_fops; - -struct irda_entry { - const char *name; - const struct file_operations *fops; -}; - -struct proc_dir_entry *proc_irda; -EXPORT_SYMBOL(proc_irda); - -static const struct irda_entry irda_dirs[] = { - {"discovery", &discovery_seq_fops}, - {"irttp", &irttp_seq_fops}, - {"irlmp", &irlmp_seq_fops}, - {"irlap", &irlap_seq_fops}, - {"irias", &irias_seq_fops}, -}; - -/* - * Function irda_proc_register (void) - * - * Register irda entry in /proc file system - * - */ -void __init irda_proc_register(void) -{ - int i; - - proc_irda = proc_mkdir("irda", init_net.proc_net); - if (proc_irda == NULL) - return; - - for (i = 0; i < ARRAY_SIZE(irda_dirs); i++) - (void) proc_create(irda_dirs[i].name, 0, proc_irda, - irda_dirs[i].fops); -} - -/* - * Function irda_proc_unregister (void) - * - * Unregister irda entry in /proc file system - * - */ -void irda_proc_unregister(void) -{ - int i; - - if (proc_irda) { - for (i=0; i<ARRAY_SIZE(irda_dirs); i++) - remove_proc_entry(irda_dirs[i].name, proc_irda); - - remove_proc_entry("irda", init_net.proc_net); - proc_irda = NULL; - } -} - - diff --git a/drivers/staging/irda/net/irqueue.c b/drivers/staging/irda/net/irqueue.c deleted file mode 100644 index 14291cbc4097..000000000000 --- a/drivers/staging/irda/net/irqueue.c +++ /dev/null @@ -1,912 +0,0 @@ -/********************************************************************* - * - * Filename: irqueue.c - * Version: 0.3 - * Description: General queue implementation - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Jun 9 13:29:31 1998 - * Modified at: Sun Dec 12 13:48:22 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Modified at: Thu Jan 4 14:29:10 CET 2001 - * Modified by: Marc Zyngier <mzyngier@freesurf.fr> - * - * Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no> - * Copyright (C) 1998, Dag Brattli, - * All Rights Reserved. - * - * This code is taken from the Vortex Operating System written by Aage - * Kvalnes. Aage has agreed that this code can use the GPL licence, - * although he does not use that licence in his own code. - * - * This copyright does however _not_ include the ELF hash() function - * which I currently don't know which licence or copyright it - * has. Please inform me if you know. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -/* - * NOTE : - * There are various problems with this package : - * o the hash function for ints is pathetic (but could be changed) - * o locking is sometime suspicious (especially during enumeration) - * o most users have only a few elements (== overhead) - * o most users never use search, so don't benefit from hashing - * Problem already fixed : - * o not 64 bit compliant (most users do hashv = (int) self) - * o hashbin_remove() is broken => use hashbin_remove_this() - * I think most users would be better served by a simple linked list - * (like include/linux/list.h) with a global spinlock per list. - * Jean II - */ - -/* - * Notes on the concurrent access to hashbin and other SMP issues - * ------------------------------------------------------------- - * Hashbins are very often in the IrDA stack a global repository of - * information, and therefore used in a very asynchronous manner following - * various events (driver calls, timers, user calls...). - * Therefore, very often it is highly important to consider the - * management of concurrent access to the hashbin and how to guarantee the - * consistency of the operations on it. - * - * First, we need to define the objective of locking : - * 1) Protect user data (content pointed by the hashbin) - * 2) Protect hashbin structure itself (linked list in each bin) - * - * OLD LOCKING - * ----------- - * - * The previous locking strategy, either HB_LOCAL or HB_GLOBAL were - * both inadequate in *both* aspect. - * o HB_GLOBAL was using a spinlock for each bin (local locking). - * o HB_LOCAL was disabling irq on *all* CPUs, so use a single - * global semaphore. - * The problems were : - * A) Global irq disabling is no longer supported by the kernel - * B) No protection for the hashbin struct global data - * o hashbin_delete() - * o hb_current - * C) No protection for user data in some cases - * - * A) HB_LOCAL use global irq disabling, so doesn't work on kernel - * 2.5.X. Even when it is supported (kernel 2.4.X and earlier), its - * performance is not satisfactory on SMP setups. Most hashbins were - * HB_LOCAL, so (A) definitely need fixing. - * B) HB_LOCAL could be modified to fix (B). However, because HB_GLOBAL - * lock only the individual bins, it will never be able to lock the - * global data, so can't do (B). - * C) Some functions return pointer to data that is still in the - * hashbin : - * o hashbin_find() - * o hashbin_get_first() - * o hashbin_get_next() - * As the data is still in the hashbin, it may be changed or free'd - * while the caller is examinimg the data. In those case, locking can't - * be done within the hashbin, but must include use of the data within - * the caller. - * The caller can easily do this with HB_LOCAL (just disable irqs). - * However, this is impossible with HB_GLOBAL because the caller has no - * way to know the proper bin, so don't know which spinlock to use. - * - * Quick summary : can no longer use HB_LOCAL, and HB_GLOBAL is - * fundamentally broken and will never work. - * - * NEW LOCKING - * ----------- - * - * To fix those problems, I've introduce a few changes in the - * hashbin locking : - * 1) New HB_LOCK scheme - * 2) hashbin->hb_spinlock - * 3) New hashbin usage policy - * - * HB_LOCK : - * ------- - * HB_LOCK is a locking scheme intermediate between the old HB_LOCAL - * and HB_GLOBAL. It uses a single spinlock to protect the whole content - * of the hashbin. As it is a single spinlock, it can protect the global - * data of the hashbin and not only the bins themselves. - * HB_LOCK can only protect some of the hashbin calls, so it only lock - * call that can be made 100% safe and leave other call unprotected. - * HB_LOCK in theory is slower than HB_GLOBAL, but as the hashbin - * content is always small contention is not high, so it doesn't matter - * much. HB_LOCK is probably faster than HB_LOCAL. - * - * hashbin->hb_spinlock : - * -------------------- - * The spinlock that HB_LOCK uses is available for caller, so that - * the caller can protect unprotected calls (see below). - * If the caller want to do entirely its own locking (HB_NOLOCK), he - * can do so and may use safely this spinlock. - * Locking is done like this : - * spin_lock_irqsave(&hashbin->hb_spinlock, flags); - * Releasing the lock : - * spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - * - * Safe & Protected calls : - * ---------------------- - * The following calls are safe or protected via HB_LOCK : - * o hashbin_new() -> safe - * o hashbin_delete() - * o hashbin_insert() - * o hashbin_remove_first() - * o hashbin_remove() - * o hashbin_remove_this() - * o HASHBIN_GET_SIZE() -> atomic - * - * The following calls only protect the hashbin itself : - * o hashbin_lock_find() - * o hashbin_find_next() - * - * Unprotected calls : - * ----------------- - * The following calls need to be protected by the caller : - * o hashbin_find() - * o hashbin_get_first() - * o hashbin_get_next() - * - * Locking Policy : - * -------------- - * If the hashbin is used only in a single thread of execution - * (explicitly or implicitely), you can use HB_NOLOCK - * If the calling module already provide concurrent access protection, - * you may use HB_NOLOCK. - * - * In all other cases, you need to use HB_LOCK and lock the hashbin - * every time before calling one of the unprotected calls. You also must - * use the pointer returned by the unprotected call within the locked - * region. - * - * Extra care for enumeration : - * -------------------------- - * hashbin_get_first() and hashbin_get_next() use the hashbin to - * store the current position, in hb_current. - * As long as the hashbin remains locked, this is safe. If you unlock - * the hashbin, the current position may change if anybody else modify - * or enumerate the hashbin. - * Summary : do the full enumeration while locked. - * - * Alternatively, you may use hashbin_find_next(). But, this will - * be slower, is more complex to use and doesn't protect the hashbin - * content. So, care is needed here as well. - * - * Other issues : - * ------------ - * I believe that we are overdoing it by using spin_lock_irqsave() - * and we should use only spin_lock_bh() or similar. But, I don't have - * the balls to try it out. - * Don't believe that because hashbin are now (somewhat) SMP safe - * that the rest of the code is. Higher layers tend to be safest, - * but LAP and LMP would need some serious dedicated love. - * - * Jean II - */ -#include <linux/module.h> -#include <linux/slab.h> - -#include <net/irda/irda.h> -#include <net/irda/irqueue.h> - -/************************ QUEUE SUBROUTINES ************************/ - -/* - * Hashbin - */ -#define GET_HASHBIN(x) ( x & HASHBIN_MASK ) - -/* - * Function hash (name) - * - * This function hash the input string 'name' using the ELF hash - * function for strings. - */ -static __u32 hash( const char* name) -{ - __u32 h = 0; - __u32 g; - - while(*name) { - h = (h<<4) + *name++; - g = h & 0xf0000000; - if (g) - h ^=g>>24; - h &=~g; - } - return h; -} - -/* - * Function enqueue_first (queue, proc) - * - * Insert item first in queue. - * - */ -static void enqueue_first(irda_queue_t **queue, irda_queue_t* element) -{ - - /* - * Check if queue is empty. - */ - if ( *queue == NULL ) { - /* - * Queue is empty. Insert one element into the queue. - */ - element->q_next = element->q_prev = *queue = element; - - } else { - /* - * Queue is not empty. Insert element into front of queue. - */ - element->q_next = (*queue); - (*queue)->q_prev->q_next = element; - element->q_prev = (*queue)->q_prev; - (*queue)->q_prev = element; - (*queue) = element; - } -} - - -/* - * Function dequeue (queue) - * - * Remove first entry in queue - * - */ -static irda_queue_t *dequeue_first(irda_queue_t **queue) -{ - irda_queue_t *ret; - - pr_debug("dequeue_first()\n"); - - /* - * Set return value - */ - ret = *queue; - - if ( *queue == NULL ) { - /* - * Queue was empty. - */ - } else if ( (*queue)->q_next == *queue ) { - /* - * Queue only contained a single element. It will now be - * empty. - */ - *queue = NULL; - } else { - /* - * Queue contained several element. Remove the first one. - */ - (*queue)->q_prev->q_next = (*queue)->q_next; - (*queue)->q_next->q_prev = (*queue)->q_prev; - *queue = (*queue)->q_next; - } - - /* - * Return the removed entry (or NULL of queue was empty). - */ - return ret; -} - -/* - * Function dequeue_general (queue, element) - * - * - */ -static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element) -{ - irda_queue_t *ret; - - pr_debug("dequeue_general()\n"); - - /* - * Set return value - */ - ret = *queue; - - if ( *queue == NULL ) { - /* - * Queue was empty. - */ - } else if ( (*queue)->q_next == *queue ) { - /* - * Queue only contained a single element. It will now be - * empty. - */ - *queue = NULL; - - } else { - /* - * Remove specific element. - */ - element->q_prev->q_next = element->q_next; - element->q_next->q_prev = element->q_prev; - if ( (*queue) == element) - (*queue) = element->q_next; - } - - /* - * Return the removed entry (or NULL of queue was empty). - */ - return ret; -} - -/************************ HASHBIN MANAGEMENT ************************/ - -/* - * Function hashbin_create ( type, name ) - * - * Create hashbin! - * - */ -hashbin_t *hashbin_new(int type) -{ - hashbin_t* hashbin; - - /* - * Allocate new hashbin - */ - hashbin = kzalloc(sizeof(*hashbin), GFP_ATOMIC); - if (!hashbin) - return NULL; - - /* - * Initialize structure - */ - hashbin->hb_type = type; - hashbin->magic = HB_MAGIC; - //hashbin->hb_current = NULL; - - /* Make sure all spinlock's are unlocked */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_lock_init(&hashbin->hb_spinlock); - } - - return hashbin; -} -EXPORT_SYMBOL(hashbin_new); - - -/* - * Function hashbin_delete (hashbin, free_func) - * - * Destroy hashbin, the free_func can be a user supplied special routine - * for deallocating this structure if it's complex. If not the user can - * just supply kfree, which should take care of the job. - */ -int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func) -{ - irda_queue_t* queue; - unsigned long flags = 0; - int i; - - IRDA_ASSERT(hashbin != NULL, return -1;); - IRDA_ASSERT(hashbin->magic == HB_MAGIC, return -1;); - - /* Synchronize */ - if (hashbin->hb_type & HB_LOCK) - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - - /* - * Free the entries in the hashbin, TODO: use hashbin_clear when - * it has been shown to work - */ - for (i = 0; i < HASHBIN_SIZE; i ++ ) { - while (1) { - queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]); - - if (!queue) - break; - - if (free_func) { - if (hashbin->hb_type & HB_LOCK) - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - free_func(queue); - if (hashbin->hb_type & HB_LOCK) - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - } - } - } - - /* Cleanup local data */ - hashbin->hb_current = NULL; - hashbin->magic = ~HB_MAGIC; - - /* Release lock */ - if (hashbin->hb_type & HB_LOCK) - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - - /* - * Free the hashbin structure - */ - kfree(hashbin); - - return 0; -} -EXPORT_SYMBOL(hashbin_delete); - -/********************* HASHBIN LIST OPERATIONS *********************/ - -/* - * Function hashbin_insert (hashbin, entry, name) - * - * Insert an entry into the hashbin - * - */ -void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, - const char* name) -{ - unsigned long flags = 0; - int bin; - - IRDA_ASSERT( hashbin != NULL, return;); - IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;); - - /* - * Locate hashbin - */ - if ( name ) - hashv = hash( name ); - bin = GET_HASHBIN( hashv ); - - /* Synchronize */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ - - /* - * Store name and key - */ - entry->q_hash = hashv; - if ( name ) - strlcpy( entry->q_name, name, sizeof(entry->q_name)); - - /* - * Insert new entry first - */ - enqueue_first( (irda_queue_t**) &hashbin->hb_queue[ bin ], - entry); - hashbin->hb_size++; - - /* Release lock */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ -} -EXPORT_SYMBOL(hashbin_insert); - -/* - * Function hashbin_remove_first (hashbin) - * - * Remove first entry of the hashbin - * - * Note : this function no longer use hashbin_remove(), but does things - * similar to hashbin_remove_this(), so can be considered safe. - * Jean II - */ -void *hashbin_remove_first( hashbin_t *hashbin) -{ - unsigned long flags = 0; - irda_queue_t *entry = NULL; - - /* Synchronize */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ - - entry = hashbin_get_first( hashbin); - if ( entry != NULL) { - int bin; - long hashv; - /* - * Locate hashbin - */ - hashv = entry->q_hash; - bin = GET_HASHBIN( hashv ); - - /* - * Dequeue the entry... - */ - dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ], - entry); - hashbin->hb_size--; - entry->q_next = NULL; - entry->q_prev = NULL; - - /* - * Check if this item is the currently selected item, and in - * that case we must reset hb_current - */ - if ( entry == hashbin->hb_current) - hashbin->hb_current = NULL; - } - - /* Release lock */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ - - return entry; -} - - -/* - * Function hashbin_remove (hashbin, hashv, name) - * - * Remove entry with the given name - * - * The use of this function is highly discouraged, because the whole - * concept behind hashbin_remove() is broken. In many cases, it's not - * possible to guarantee the unicity of the index (either hashv or name), - * leading to removing the WRONG entry. - * The only simple safe use is : - * hashbin_remove(hasbin, (int) self, NULL); - * In other case, you must think hard to guarantee unicity of the index. - * Jean II - */ -void* hashbin_remove( hashbin_t* hashbin, long hashv, const char* name) -{ - int bin, found = FALSE; - unsigned long flags = 0; - irda_queue_t* entry; - - IRDA_ASSERT( hashbin != NULL, return NULL;); - IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); - - /* - * Locate hashbin - */ - if ( name ) - hashv = hash( name ); - bin = GET_HASHBIN( hashv ); - - /* Synchronize */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ - - /* - * Search for entry - */ - entry = hashbin->hb_queue[ bin ]; - if ( entry ) { - do { - /* - * Check for key - */ - if ( entry->q_hash == hashv ) { - /* - * Name compare too? - */ - if ( name ) { - if ( strcmp( entry->q_name, name) == 0) - { - found = TRUE; - break; - } - } else { - found = TRUE; - break; - } - } - entry = entry->q_next; - } while ( entry != hashbin->hb_queue[ bin ] ); - } - - /* - * If entry was found, dequeue it - */ - if ( found ) { - dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ], - entry); - hashbin->hb_size--; - - /* - * Check if this item is the currently selected item, and in - * that case we must reset hb_current - */ - if ( entry == hashbin->hb_current) - hashbin->hb_current = NULL; - } - - /* Release lock */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ - - - /* Return */ - if ( found ) - return entry; - else - return NULL; - -} -EXPORT_SYMBOL(hashbin_remove); - -/* - * Function hashbin_remove_this (hashbin, entry) - * - * Remove entry with the given name - * - * In some cases, the user of hashbin can't guarantee the unicity - * of either the hashv or name. - * In those cases, using the above function is guaranteed to cause troubles, - * so we use this one instead... - * And by the way, it's also faster, because we skip the search phase ;-) - */ -void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry) -{ - unsigned long flags = 0; - int bin; - long hashv; - - IRDA_ASSERT( hashbin != NULL, return NULL;); - IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); - IRDA_ASSERT( entry != NULL, return NULL;); - - /* Synchronize */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ - - /* Check if valid and not already removed... */ - if((entry->q_next == NULL) || (entry->q_prev == NULL)) { - entry = NULL; - goto out; - } - - /* - * Locate hashbin - */ - hashv = entry->q_hash; - bin = GET_HASHBIN( hashv ); - - /* - * Dequeue the entry... - */ - dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ], - entry); - hashbin->hb_size--; - entry->q_next = NULL; - entry->q_prev = NULL; - - /* - * Check if this item is the currently selected item, and in - * that case we must reset hb_current - */ - if ( entry == hashbin->hb_current) - hashbin->hb_current = NULL; -out: - /* Release lock */ - if ( hashbin->hb_type & HB_LOCK ) { - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - } /* Default is no-lock */ - - return entry; -} -EXPORT_SYMBOL(hashbin_remove_this); - -/*********************** HASHBIN ENUMERATION ***********************/ - -/* - * Function hashbin_common_find (hashbin, hashv, name) - * - * Find item with the given hashv or name - * - */ -void* hashbin_find( hashbin_t* hashbin, long hashv, const char* name ) -{ - int bin; - irda_queue_t* entry; - - pr_debug("hashbin_find()\n"); - - IRDA_ASSERT( hashbin != NULL, return NULL;); - IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); - - /* - * Locate hashbin - */ - if ( name ) - hashv = hash( name ); - bin = GET_HASHBIN( hashv ); - - /* - * Search for entry - */ - entry = hashbin->hb_queue[ bin]; - if ( entry ) { - do { - /* - * Check for key - */ - if ( entry->q_hash == hashv ) { - /* - * Name compare too? - */ - if ( name ) { - if ( strcmp( entry->q_name, name ) == 0 ) { - return entry; - } - } else { - return entry; - } - } - entry = entry->q_next; - } while ( entry != hashbin->hb_queue[ bin ] ); - } - - return NULL; -} -EXPORT_SYMBOL(hashbin_find); - -/* - * Function hashbin_lock_find (hashbin, hashv, name) - * - * Find item with the given hashv or name - * - * Same, but with spinlock protection... - * I call it safe, but it's only safe with respect to the hashbin, not its - * content. - Jean II - */ -void* hashbin_lock_find( hashbin_t* hashbin, long hashv, const char* name ) -{ - unsigned long flags = 0; - irda_queue_t* entry; - - /* Synchronize */ - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - - /* - * Search for entry - */ - entry = hashbin_find(hashbin, hashv, name); - - /* Release lock */ - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - - return entry; -} -EXPORT_SYMBOL(hashbin_lock_find); - -/* - * Function hashbin_find (hashbin, hashv, name, pnext) - * - * Find an item with the given hashv or name, and its successor - * - * This function allow to do concurrent enumerations without the - * need to lock over the whole session, because the caller keep the - * context of the search. On the other hand, it might fail and return - * NULL if the entry is removed. - Jean II - */ -void* hashbin_find_next( hashbin_t* hashbin, long hashv, const char* name, - void ** pnext) -{ - unsigned long flags = 0; - irda_queue_t* entry; - - /* Synchronize */ - spin_lock_irqsave(&hashbin->hb_spinlock, flags); - - /* - * Search for current entry - * This allow to check if the current item is still in the - * hashbin or has been removed. - */ - entry = hashbin_find(hashbin, hashv, name); - - /* - * Trick hashbin_get_next() to return what we want - */ - if(entry) { - hashbin->hb_current = entry; - *pnext = hashbin_get_next( hashbin ); - } else - *pnext = NULL; - - /* Release lock */ - spin_unlock_irqrestore(&hashbin->hb_spinlock, flags); - - return entry; -} - -/* - * Function hashbin_get_first (hashbin) - * - * Get a pointer to first element in hashbin, this function must be - * called before any calls to hashbin_get_next()! - * - */ -irda_queue_t *hashbin_get_first( hashbin_t* hashbin) -{ - irda_queue_t *entry; - int i; - - IRDA_ASSERT( hashbin != NULL, return NULL;); - IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); - - if ( hashbin == NULL) - return NULL; - - for ( i = 0; i < HASHBIN_SIZE; i ++ ) { - entry = hashbin->hb_queue[ i]; - if ( entry) { - hashbin->hb_current = entry; - return entry; - } - } - /* - * Did not find any item in hashbin - */ - return NULL; -} -EXPORT_SYMBOL(hashbin_get_first); - -/* - * Function hashbin_get_next (hashbin) - * - * Get next item in hashbin. A series of hashbin_get_next() calls must - * be started by a call to hashbin_get_first(). The function returns - * NULL when all items have been traversed - * - * The context of the search is stored within the hashbin, so you must - * protect yourself from concurrent enumerations. - Jean II - */ -irda_queue_t *hashbin_get_next( hashbin_t *hashbin) -{ - irda_queue_t* entry; - int bin; - int i; - - IRDA_ASSERT( hashbin != NULL, return NULL;); - IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); - - if ( hashbin->hb_current == NULL) { - IRDA_ASSERT( hashbin->hb_current != NULL, return NULL;); - return NULL; - } - entry = hashbin->hb_current->q_next; - bin = GET_HASHBIN( entry->q_hash); - - /* - * Make sure that we are not back at the beginning of the queue - * again - */ - if ( entry != hashbin->hb_queue[ bin ]) { - hashbin->hb_current = entry; - - return entry; - } - - /* - * Check that this is not the last queue in hashbin - */ - if ( bin >= HASHBIN_SIZE) - return NULL; - - /* - * Move to next queue in hashbin - */ - bin++; - for ( i = bin; i < HASHBIN_SIZE; i++ ) { - entry = hashbin->hb_queue[ i]; - if ( entry) { - hashbin->hb_current = entry; - - return entry; - } - } - return NULL; -} -EXPORT_SYMBOL(hashbin_get_next); diff --git a/drivers/staging/irda/net/irsysctl.c b/drivers/staging/irda/net/irsysctl.c deleted file mode 100644 index 873da5e7d428..000000000000 --- a/drivers/staging/irda/net/irsysctl.c +++ /dev/null @@ -1,258 +0,0 @@ -/********************************************************************* - * - * Filename: irsysctl.c - * Version: 1.0 - * Description: Sysctl interface for IrDA - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun May 24 22:12:06 1998 - * Modified at: Fri Jun 4 02:50:15 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/mm.h> -#include <linux/ctype.h> -#include <linux/sysctl.h> -#include <linux/init.h> - -#include <net/irda/irda.h> /* irda_debug */ -#include <net/irda/irlmp.h> -#include <net/irda/timer.h> -#include <net/irda/irias_object.h> - -extern int sysctl_discovery; -extern int sysctl_discovery_slots; -extern int sysctl_discovery_timeout; -extern int sysctl_slot_timeout; -extern int sysctl_fast_poll_increase; -extern char sysctl_devname[]; -extern int sysctl_max_baud_rate; -extern unsigned int sysctl_min_tx_turn_time; -extern unsigned int sysctl_max_tx_data_size; -extern unsigned int sysctl_max_tx_window; -extern int sysctl_max_noreply_time; -extern int sysctl_warn_noreply_time; -extern int sysctl_lap_keepalive_time; - -extern struct irlmp_cb *irlmp; - -/* this is needed for the proc_dointvec_minmax - Jean II */ -static int max_discovery_slots = 16; /* ??? */ -static int min_discovery_slots = 1; -/* IrLAP 6.13.2 says 25ms to 10+70ms - allow higher since some devices - * seems to require it. (from Dag's comment) */ -static int max_slot_timeout = 160; -static int min_slot_timeout = 20; -static int max_max_baud_rate = 16000000; /* See qos.c - IrLAP spec */ -static int min_max_baud_rate = 2400; -static int max_min_tx_turn_time = 10000; /* See qos.c - IrLAP spec */ -static int min_min_tx_turn_time; -static int max_max_tx_data_size = 2048; /* See qos.c - IrLAP spec */ -static int min_max_tx_data_size = 64; -static int max_max_tx_window = 7; /* See qos.c - IrLAP spec */ -static int min_max_tx_window = 1; -static int max_max_noreply_time = 40; /* See qos.c - IrLAP spec */ -static int min_max_noreply_time = 3; -static int max_warn_noreply_time = 3; /* 3s == standard */ -static int min_warn_noreply_time = 1; /* 1s == min WD_TIMER */ -static int max_lap_keepalive_time = 10000; /* 10s */ -static int min_lap_keepalive_time = 100; /* 100us */ -/* For other sysctl, I've no idea of the range. Maybe Dag could help - * us on that - Jean II */ - -static int do_devname(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int ret; - - ret = proc_dostring(table, write, buffer, lenp, ppos); - if (ret == 0 && write) { - struct ias_value *val; - - val = irias_new_string_value(sysctl_devname); - if (val) - irias_object_change_attribute("Device", "DeviceName", val); - } - return ret; -} - - -static int do_discovery(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int ret; - - ret = proc_dointvec(table, write, buffer, lenp, ppos); - if (ret) - return ret; - - if (irlmp == NULL) - return -ENODEV; - - if (sysctl_discovery) - irlmp_start_discovery_timer(irlmp, sysctl_discovery_timeout*HZ); - else - del_timer_sync(&irlmp->discovery_timer); - - return ret; -} - -/* One file */ -static struct ctl_table irda_table[] = { - { - .procname = "discovery", - .data = &sysctl_discovery, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = do_discovery, - }, - { - .procname = "devname", - .data = sysctl_devname, - .maxlen = 65, - .mode = 0644, - .proc_handler = do_devname, - }, -#ifdef CONFIG_IRDA_FAST_RR - { - .procname = "fast_poll_increase", - .data = &sysctl_fast_poll_increase, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#endif - { - .procname = "discovery_slots", - .data = &sysctl_discovery_slots, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_discovery_slots, - .extra2 = &max_discovery_slots - }, - { - .procname = "discovery_timeout", - .data = &sysctl_discovery_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "slot_timeout", - .data = &sysctl_slot_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_slot_timeout, - .extra2 = &max_slot_timeout - }, - { - .procname = "max_baud_rate", - .data = &sysctl_max_baud_rate, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_max_baud_rate, - .extra2 = &max_max_baud_rate - }, - { - .procname = "min_tx_turn_time", - .data = &sysctl_min_tx_turn_time, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_min_tx_turn_time, - .extra2 = &max_min_tx_turn_time - }, - { - .procname = "max_tx_data_size", - .data = &sysctl_max_tx_data_size, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_max_tx_data_size, - .extra2 = &max_max_tx_data_size - }, - { - .procname = "max_tx_window", - .data = &sysctl_max_tx_window, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_max_tx_window, - .extra2 = &max_max_tx_window - }, - { - .procname = "max_noreply_time", - .data = &sysctl_max_noreply_time, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_max_noreply_time, - .extra2 = &max_max_noreply_time - }, - { - .procname = "warn_noreply_time", - .data = &sysctl_warn_noreply_time, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_warn_noreply_time, - .extra2 = &max_warn_noreply_time - }, - { - .procname = "lap_keepalive_time", - .data = &sysctl_lap_keepalive_time, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_lap_keepalive_time, - .extra2 = &max_lap_keepalive_time - }, - { } -}; - -static struct ctl_table_header *irda_table_header; - -/* - * Function irda_sysctl_register (void) - * - * Register our sysctl interface - * - */ -int __init irda_sysctl_register(void) -{ - irda_table_header = register_net_sysctl(&init_net, "net/irda", irda_table); - if (!irda_table_header) - return -ENOMEM; - - return 0; -} - -/* - * Function irda_sysctl_unregister (void) - * - * Unregister our sysctl interface - * - */ -void irda_sysctl_unregister(void) -{ - unregister_net_sysctl_table(irda_table_header); -} - - - diff --git a/drivers/staging/irda/net/irttp.c b/drivers/staging/irda/net/irttp.c deleted file mode 100644 index 741a94f39b4e..000000000000 --- a/drivers/staging/irda/net/irttp.c +++ /dev/null @@ -1,1886 +0,0 @@ -/********************************************************************* - * - * Filename: irttp.c - * Version: 1.2 - * Description: Tiny Transport Protocol (TTP) implementation - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 31 20:14:31 1997 - * Modified at: Wed Jan 5 11:31:27 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/skbuff.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <linux/export.h> - -#include <asm/byteorder.h> -#include <asm/unaligned.h> - -#include <net/irda/irda.h> -#include <net/irda/irlap.h> -#include <net/irda/irlmp.h> -#include <net/irda/parameters.h> -#include <net/irda/irttp.h> - -static struct irttp_cb *irttp; - -static void __irttp_close_tsap(struct tsap_cb *self); - -static int irttp_data_indication(void *instance, void *sap, - struct sk_buff *skb); -static int irttp_udata_indication(void *instance, void *sap, - struct sk_buff *skb); -static void irttp_disconnect_indication(void *instance, void *sap, - LM_REASON reason, struct sk_buff *); -static void irttp_connect_indication(void *instance, void *sap, - struct qos_info *qos, __u32 max_sdu_size, - __u8 header_size, struct sk_buff *skb); -static void irttp_connect_confirm(void *instance, void *sap, - struct qos_info *qos, __u32 max_sdu_size, - __u8 header_size, struct sk_buff *skb); -static void irttp_run_tx_queue(struct tsap_cb *self); -static void irttp_run_rx_queue(struct tsap_cb *self); - -static void irttp_flush_queues(struct tsap_cb *self); -static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb); -static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self); -static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, - int get); - -static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow); -static void irttp_status_indication(void *instance, - LINK_STATUS link, LOCK_STATUS lock); - -/* Information for parsing parameters in IrTTP */ -static const pi_minor_info_t pi_minor_call_table[] = { - { NULL, 0 }, /* 0x00 */ - { irttp_param_max_sdu_size, PV_INTEGER | PV_BIG_ENDIAN } /* 0x01 */ -}; -static const pi_major_info_t pi_major_call_table[] = { - { pi_minor_call_table, 2 } -}; -static pi_param_info_t param_info = { pi_major_call_table, 1, 0x0f, 4 }; - -/************************ GLOBAL PROCEDURES ************************/ - -/* - * Function irttp_init (void) - * - * Initialize the IrTTP layer. Called by module initialization code - * - */ -int __init irttp_init(void) -{ - irttp = kzalloc(sizeof(struct irttp_cb), GFP_KERNEL); - if (irttp == NULL) - return -ENOMEM; - - irttp->magic = TTP_MAGIC; - - irttp->tsaps = hashbin_new(HB_LOCK); - if (!irttp->tsaps) { - net_err_ratelimited("%s: can't allocate IrTTP hashbin!\n", - __func__); - kfree(irttp); - return -ENOMEM; - } - - return 0; -} - -/* - * Function irttp_cleanup (void) - * - * Called by module destruction/cleanup code - * - */ -void irttp_cleanup(void) -{ - /* Check for main structure */ - IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;); - - /* - * Delete hashbin and close all TSAP instances in it - */ - hashbin_delete(irttp->tsaps, (FREE_FUNC) __irttp_close_tsap); - - irttp->magic = 0; - - /* De-allocate main structure */ - kfree(irttp); - - irttp = NULL; -} - -/*************************** SUBROUTINES ***************************/ - -/* - * Function irttp_start_todo_timer (self, timeout) - * - * Start todo timer. - * - * Made it more effient and unsensitive to race conditions - Jean II - */ -static inline void irttp_start_todo_timer(struct tsap_cb *self, int timeout) -{ - /* Set new value for timer */ - mod_timer(&self->todo_timer, jiffies + timeout); -} - -/* - * Function irttp_todo_expired (data) - * - * Todo timer has expired! - * - * One of the restriction of the timer is that it is run only on the timer - * interrupt which run every 10ms. This mean that even if you set the timer - * with a delay of 0, it may take up to 10ms before it's run. - * So, to minimise latency and keep cache fresh, we try to avoid using - * it as much as possible. - * Note : we can't use tasklets, because they can't be asynchronously - * killed (need user context), and we can't guarantee that here... - * Jean II - */ -static void irttp_todo_expired(struct timer_list *t) -{ - struct tsap_cb *self = from_timer(self, t, todo_timer); - - /* Check that we still exist */ - if (!self || self->magic != TTP_TSAP_MAGIC) - return; - - pr_debug("%s(instance=%p)\n", __func__, self); - - /* Try to make some progress, especially on Tx side - Jean II */ - irttp_run_rx_queue(self); - irttp_run_tx_queue(self); - - /* Check if time for disconnect */ - if (test_bit(0, &self->disconnect_pend)) { - /* Check if it's possible to disconnect yet */ - if (skb_queue_empty(&self->tx_queue)) { - /* Make sure disconnect is not pending anymore */ - clear_bit(0, &self->disconnect_pend); /* FALSE */ - - /* Note : self->disconnect_skb may be NULL */ - irttp_disconnect_request(self, self->disconnect_skb, - P_NORMAL); - self->disconnect_skb = NULL; - } else { - /* Try again later */ - irttp_start_todo_timer(self, HZ/10); - - /* No reason to try and close now */ - return; - } - } - - /* Check if it's closing time */ - if (self->close_pend) - /* Finish cleanup */ - irttp_close_tsap(self); -} - -/* - * Function irttp_flush_queues (self) - * - * Flushes (removes all frames) in transitt-buffer (tx_list) - */ -static void irttp_flush_queues(struct tsap_cb *self) -{ - struct sk_buff *skb; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - - /* Deallocate frames waiting to be sent */ - while ((skb = skb_dequeue(&self->tx_queue)) != NULL) - dev_kfree_skb(skb); - - /* Deallocate received frames */ - while ((skb = skb_dequeue(&self->rx_queue)) != NULL) - dev_kfree_skb(skb); - - /* Deallocate received fragments */ - while ((skb = skb_dequeue(&self->rx_fragments)) != NULL) - dev_kfree_skb(skb); -} - -/* - * Function irttp_reassemble (self) - * - * Makes a new (continuous) skb of all the fragments in the fragment - * queue - * - */ -static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self) -{ - struct sk_buff *skb, *frag; - int n = 0; /* Fragment index */ - - IRDA_ASSERT(self != NULL, return NULL;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;); - - pr_debug("%s(), self->rx_sdu_size=%d\n", __func__, - self->rx_sdu_size); - - skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size); - if (!skb) - return NULL; - - /* - * Need to reserve space for TTP header in case this skb needs to - * be requeued in case delivery failes - */ - skb_reserve(skb, TTP_HEADER); - skb_put(skb, self->rx_sdu_size); - - /* - * Copy all fragments to a new buffer - */ - while ((frag = skb_dequeue(&self->rx_fragments)) != NULL) { - skb_copy_to_linear_data_offset(skb, n, frag->data, frag->len); - n += frag->len; - - dev_kfree_skb(frag); - } - - pr_debug("%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n", - __func__, n, self->rx_sdu_size, self->rx_max_sdu_size); - /* Note : irttp_run_rx_queue() calculate self->rx_sdu_size - * by summing the size of all fragments, so we should always - * have n == self->rx_sdu_size, except in cases where we - * droped the last fragment (when self->rx_sdu_size exceed - * self->rx_max_sdu_size), where n < self->rx_sdu_size. - * Jean II */ - IRDA_ASSERT(n <= self->rx_sdu_size, n = self->rx_sdu_size;); - - /* Set the new length */ - skb_trim(skb, n); - - self->rx_sdu_size = 0; - - return skb; -} - -/* - * Function irttp_fragment_skb (skb) - * - * Fragments a frame and queues all the fragments for transmission - * - */ -static inline void irttp_fragment_skb(struct tsap_cb *self, - struct sk_buff *skb) -{ - struct sk_buff *frag; - __u8 *frame; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - /* - * Split frame into a number of segments - */ - while (skb->len > self->max_seg_size) { - pr_debug("%s(), fragmenting ...\n", __func__); - - /* Make new segment */ - frag = alloc_skb(self->max_seg_size+self->max_header_size, - GFP_ATOMIC); - if (!frag) - return; - - skb_reserve(frag, self->max_header_size); - - /* Copy data from the original skb into this fragment. */ - skb_copy_from_linear_data(skb, skb_put(frag, self->max_seg_size), - self->max_seg_size); - - /* Insert TTP header, with the more bit set */ - frame = skb_push(frag, TTP_HEADER); - frame[0] = TTP_MORE; - - /* Hide the copied data from the original skb */ - skb_pull(skb, self->max_seg_size); - - /* Queue fragment */ - skb_queue_tail(&self->tx_queue, frag); - } - /* Queue what is left of the original skb */ - pr_debug("%s(), queuing last segment\n", __func__); - - frame = skb_push(skb, TTP_HEADER); - frame[0] = 0x00; /* Clear more bit */ - - /* Queue fragment */ - skb_queue_tail(&self->tx_queue, skb); -} - -/* - * Function irttp_param_max_sdu_size (self, param) - * - * Handle the MaxSduSize parameter in the connect frames, this function - * will be called both when this parameter needs to be inserted into, and - * extracted from the connect frames - */ -static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, - int get) -{ - struct tsap_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - - if (get) - param->pv.i = self->tx_max_sdu_size; - else - self->tx_max_sdu_size = param->pv.i; - - pr_debug("%s(), MaxSduSize=%d\n", __func__, param->pv.i); - - return 0; -} - -/*************************** CLIENT CALLS ***************************/ -/************************** LMP CALLBACKS **************************/ -/* Everything is happily mixed up. Waiting for next clean up - Jean II */ - -/* - * Initialization, that has to be done on new tsap - * instance allocation and on duplication - */ -static void irttp_init_tsap(struct tsap_cb *tsap) -{ - spin_lock_init(&tsap->lock); - timer_setup(&tsap->todo_timer, irttp_todo_expired, 0); - - skb_queue_head_init(&tsap->rx_queue); - skb_queue_head_init(&tsap->tx_queue); - skb_queue_head_init(&tsap->rx_fragments); -} - -/* - * Function irttp_open_tsap (stsap, notify) - * - * Create TSAP connection endpoint, - */ -struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) -{ - struct tsap_cb *self; - struct lsap_cb *lsap; - notify_t ttp_notify; - - IRDA_ASSERT(irttp->magic == TTP_MAGIC, return NULL;); - - /* The IrLMP spec (IrLMP 1.1 p10) says that we have the right to - * use only 0x01-0x6F. Of course, we can use LSAP_ANY as well. - * JeanII */ - if ((stsap_sel != LSAP_ANY) && - ((stsap_sel < 0x01) || (stsap_sel >= 0x70))) { - pr_debug("%s(), invalid tsap!\n", __func__); - return NULL; - } - - self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC); - if (self == NULL) - return NULL; - - /* Initialize internal objects */ - irttp_init_tsap(self); - - /* Initialize callbacks for IrLMP to use */ - irda_notify_init(&ttp_notify); - ttp_notify.connect_confirm = irttp_connect_confirm; - ttp_notify.connect_indication = irttp_connect_indication; - ttp_notify.disconnect_indication = irttp_disconnect_indication; - ttp_notify.data_indication = irttp_data_indication; - ttp_notify.udata_indication = irttp_udata_indication; - ttp_notify.flow_indication = irttp_flow_indication; - if (notify->status_indication != NULL) - ttp_notify.status_indication = irttp_status_indication; - ttp_notify.instance = self; - strncpy(ttp_notify.name, notify->name, NOTIFY_MAX_NAME); - - self->magic = TTP_TSAP_MAGIC; - self->connected = FALSE; - - /* - * Create LSAP at IrLMP layer - */ - lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0); - if (lsap == NULL) { - pr_debug("%s: unable to allocate LSAP!!\n", __func__); - __irttp_close_tsap(self); - return NULL; - } - - /* - * If user specified LSAP_ANY as source TSAP selector, then IrLMP - * will replace it with whatever source selector which is free, so - * the stsap_sel we have might not be valid anymore - */ - self->stsap_sel = lsap->slsap_sel; - pr_debug("%s(), stsap_sel=%02x\n", __func__, self->stsap_sel); - - self->notify = *notify; - self->lsap = lsap; - - hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (long) self, NULL); - - if (credit > TTP_RX_MAX_CREDIT) - self->initial_credit = TTP_RX_MAX_CREDIT; - else - self->initial_credit = credit; - - return self; -} -EXPORT_SYMBOL(irttp_open_tsap); - -/* - * Function irttp_close (handle) - * - * Remove an instance of a TSAP. This function should only deal with the - * deallocation of the TSAP, and resetting of the TSAPs values; - * - */ -static void __irttp_close_tsap(struct tsap_cb *self) -{ - /* First make sure we're connected. */ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - - irttp_flush_queues(self); - - del_timer(&self->todo_timer); - - /* This one won't be cleaned up if we are disconnect_pend + close_pend - * and we receive a disconnect_indication */ - if (self->disconnect_skb) - dev_kfree_skb(self->disconnect_skb); - - self->connected = FALSE; - self->magic = ~TTP_TSAP_MAGIC; - - kfree(self); -} - -/* - * Function irttp_close (self) - * - * Remove TSAP from list of all TSAPs and then deallocate all resources - * associated with this TSAP - * - * Note : because we *free* the tsap structure, it is the responsibility - * of the caller to make sure we are called only once and to deal with - * possible race conditions. - Jean II - */ -int irttp_close_tsap(struct tsap_cb *self) -{ - struct tsap_cb *tsap; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - - /* Make sure tsap has been disconnected */ - if (self->connected) { - /* Check if disconnect is not pending */ - if (!test_bit(0, &self->disconnect_pend)) { - net_warn_ratelimited("%s: TSAP still connected!\n", - __func__); - irttp_disconnect_request(self, NULL, P_NORMAL); - } - self->close_pend = TRUE; - irttp_start_todo_timer(self, HZ/10); - - return 0; /* Will be back! */ - } - - tsap = hashbin_remove(irttp->tsaps, (long) self, NULL); - - IRDA_ASSERT(tsap == self, return -1;); - - /* Close corresponding LSAP */ - if (self->lsap) { - irlmp_close_lsap(self->lsap); - self->lsap = NULL; - } - - __irttp_close_tsap(self); - - return 0; -} -EXPORT_SYMBOL(irttp_close_tsap); - -/* - * Function irttp_udata_request (self, skb) - * - * Send unreliable data on this TSAP - * - */ -int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) -{ - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - /* Take shortcut on zero byte packets */ - if (skb->len == 0) { - ret = 0; - goto err; - } - - /* Check that nothing bad happens */ - if (!self->connected) { - net_warn_ratelimited("%s(), Not connected\n", __func__); - ret = -ENOTCONN; - goto err; - } - - if (skb->len > self->max_seg_size) { - net_err_ratelimited("%s(), UData is too large for IrLAP!\n", - __func__); - ret = -EMSGSIZE; - goto err; - } - - irlmp_udata_request(self->lsap, skb); - self->stats.tx_packets++; - - return 0; - -err: - dev_kfree_skb(skb); - return ret; -} -EXPORT_SYMBOL(irttp_udata_request); - - -/* - * Function irttp_data_request (handle, skb) - * - * Queue frame for transmission. If SAR is enabled, fragement the frame - * and queue the fragments for transmission - */ -int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) -{ - __u8 *frame; - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - pr_debug("%s() : queue len = %d\n", __func__, - skb_queue_len(&self->tx_queue)); - - /* Take shortcut on zero byte packets */ - if (skb->len == 0) { - ret = 0; - goto err; - } - - /* Check that nothing bad happens */ - if (!self->connected) { - net_warn_ratelimited("%s: Not connected\n", __func__); - ret = -ENOTCONN; - goto err; - } - - /* - * Check if SAR is disabled, and the frame is larger than what fits - * inside an IrLAP frame - */ - if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) { - net_err_ratelimited("%s: SAR disabled, and data is too large for IrLAP!\n", - __func__); - ret = -EMSGSIZE; - goto err; - } - - /* - * Check if SAR is enabled, and the frame is larger than the - * TxMaxSduSize - */ - if ((self->tx_max_sdu_size != 0) && - (self->tx_max_sdu_size != TTP_SAR_UNBOUND) && - (skb->len > self->tx_max_sdu_size)) { - net_err_ratelimited("%s: SAR enabled, but data is larger than TxMaxSduSize!\n", - __func__); - ret = -EMSGSIZE; - goto err; - } - /* - * Check if transmit queue is full - */ - if (skb_queue_len(&self->tx_queue) >= TTP_TX_MAX_QUEUE) { - /* - * Give it a chance to empty itself - */ - irttp_run_tx_queue(self); - - /* Drop packet. This error code should trigger the caller - * to resend the data in the client code - Jean II */ - ret = -ENOBUFS; - goto err; - } - - /* Queue frame, or queue frame segments */ - if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) { - /* Queue frame */ - IRDA_ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;); - frame = skb_push(skb, TTP_HEADER); - frame[0] = 0x00; /* Clear more bit */ - - skb_queue_tail(&self->tx_queue, skb); - } else { - /* - * Fragment the frame, this function will also queue the - * fragments, we don't care about the fact the transmit - * queue may be overfilled by all the segments for a little - * while - */ - irttp_fragment_skb(self, skb); - } - - /* Check if we can accept more data from client */ - if ((!self->tx_sdu_busy) && - (skb_queue_len(&self->tx_queue) > TTP_TX_HIGH_THRESHOLD)) { - /* Tx queue filling up, so stop client. */ - if (self->notify.flow_indication) { - self->notify.flow_indication(self->notify.instance, - self, FLOW_STOP); - } - /* self->tx_sdu_busy is the state of the client. - * Update state after notifying client to avoid - * race condition with irttp_flow_indication(). - * If the queue empty itself after our test but before - * we set the flag, we will fix ourselves below in - * irttp_run_tx_queue(). - * Jean II */ - self->tx_sdu_busy = TRUE; - } - - /* Try to make some progress */ - irttp_run_tx_queue(self); - - return 0; - -err: - dev_kfree_skb(skb); - return ret; -} -EXPORT_SYMBOL(irttp_data_request); - -/* - * Function irttp_run_tx_queue (self) - * - * Transmit packets queued for transmission (if possible) - * - */ -static void irttp_run_tx_queue(struct tsap_cb *self) -{ - struct sk_buff *skb; - unsigned long flags; - int n; - - pr_debug("%s() : send_credit = %d, queue_len = %d\n", - __func__, - self->send_credit, skb_queue_len(&self->tx_queue)); - - /* Get exclusive access to the tx queue, otherwise don't touch it */ - if (irda_lock(&self->tx_queue_lock) == FALSE) - return; - - /* Try to send out frames as long as we have credits - * and as long as LAP is not full. If LAP is full, it will - * poll us through irttp_flow_indication() - Jean II */ - while ((self->send_credit > 0) && - (!irlmp_lap_tx_queue_full(self->lsap)) && - (skb = skb_dequeue(&self->tx_queue))) { - /* - * Since we can transmit and receive frames concurrently, - * the code below is a critical region and we must assure that - * nobody messes with the credits while we update them. - */ - spin_lock_irqsave(&self->lock, flags); - - n = self->avail_credit; - self->avail_credit = 0; - - /* Only room for 127 credits in frame */ - if (n > 127) { - self->avail_credit = n-127; - n = 127; - } - self->remote_credit += n; - self->send_credit--; - - spin_unlock_irqrestore(&self->lock, flags); - - /* - * More bit must be set by the data_request() or fragment() - * functions - */ - skb->data[0] |= (n & 0x7f); - - /* Detach from socket. - * The current skb has a reference to the socket that sent - * it (skb->sk). When we pass it to IrLMP, the skb will be - * stored in in IrLAP (self->wx_list). When we are within - * IrLAP, we lose the notion of socket, so we should not - * have a reference to a socket. So, we drop it here. - * - * Why does it matter ? - * When the skb is freed (kfree_skb), if it is associated - * with a socket, it release buffer space on the socket - * (through sock_wfree() and sock_def_write_space()). - * If the socket no longer exist, we may crash. Hard. - * When we close a socket, we make sure that associated packets - * in IrTTP are freed. However, we have no way to cancel - * the packet that we have passed to IrLAP. So, if a packet - * remains in IrLAP (retry on the link or else) after we - * close the socket, we are dead ! - * Jean II */ - if (skb->sk != NULL) { - /* IrSOCK application, IrOBEX, ... */ - skb_orphan(skb); - } - /* IrCOMM over IrTTP, IrLAN, ... */ - - /* Pass the skb to IrLMP - done */ - irlmp_data_request(self->lsap, skb); - self->stats.tx_packets++; - } - - /* Check if we can accept more frames from client. - * We don't want to wait until the todo timer to do that, and we - * can't use tasklets (grr...), so we are obliged to give control - * to client. That's ok, this test will be true not too often - * (max once per LAP window) and we are called from places - * where we can spend a bit of time doing stuff. - Jean II */ - if ((self->tx_sdu_busy) && - (skb_queue_len(&self->tx_queue) < TTP_TX_LOW_THRESHOLD) && - (!self->close_pend)) { - if (self->notify.flow_indication) - self->notify.flow_indication(self->notify.instance, - self, FLOW_START); - - /* self->tx_sdu_busy is the state of the client. - * We don't really have a race here, but it's always safer - * to update our state after the client - Jean II */ - self->tx_sdu_busy = FALSE; - } - - /* Reset lock */ - self->tx_queue_lock = 0; -} - -/* - * Function irttp_give_credit (self) - * - * Send a dataless flowdata TTP-PDU and give available credit to peer - * TSAP - */ -static inline void irttp_give_credit(struct tsap_cb *self) -{ - struct sk_buff *tx_skb = NULL; - unsigned long flags; - int n; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - - pr_debug("%s() send=%d,avail=%d,remote=%d\n", - __func__, - self->send_credit, self->avail_credit, self->remote_credit); - - /* Give credit to peer */ - tx_skb = alloc_skb(TTP_MAX_HEADER, GFP_ATOMIC); - if (!tx_skb) - return; - - /* Reserve space for LMP, and LAP header */ - skb_reserve(tx_skb, LMP_MAX_HEADER); - - /* - * Since we can transmit and receive frames concurrently, - * the code below is a critical region and we must assure that - * nobody messes with the credits while we update them. - */ - spin_lock_irqsave(&self->lock, flags); - - n = self->avail_credit; - self->avail_credit = 0; - - /* Only space for 127 credits in frame */ - if (n > 127) { - self->avail_credit = n - 127; - n = 127; - } - self->remote_credit += n; - - spin_unlock_irqrestore(&self->lock, flags); - - skb_put(tx_skb, 1); - tx_skb->data[0] = (__u8) (n & 0x7f); - - irlmp_data_request(self->lsap, tx_skb); - self->stats.tx_packets++; -} - -/* - * Function irttp_udata_indication (instance, sap, skb) - * - * Received some unit-data (unreliable) - * - */ -static int irttp_udata_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct tsap_cb *self; - int err; - - self = instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - IRDA_ASSERT(skb != NULL, return -1;); - - self->stats.rx_packets++; - - /* Just pass data to layer above */ - if (self->notify.udata_indication) { - err = self->notify.udata_indication(self->notify.instance, - self, skb); - /* Same comment as in irttp_do_data_indication() */ - if (!err) - return 0; - } - /* Either no handler, or handler returns an error */ - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irttp_data_indication (instance, sap, skb) - * - * Receive segment from IrLMP. - * - */ -static int irttp_data_indication(void *instance, void *sap, - struct sk_buff *skb) -{ - struct tsap_cb *self; - unsigned long flags; - int n; - - self = instance; - - n = skb->data[0] & 0x7f; /* Extract the credits */ - - self->stats.rx_packets++; - - /* Deal with inbound credit - * Since we can transmit and receive frames concurrently, - * the code below is a critical region and we must assure that - * nobody messes with the credits while we update them. - */ - spin_lock_irqsave(&self->lock, flags); - self->send_credit += n; - if (skb->len > 1) - self->remote_credit--; - spin_unlock_irqrestore(&self->lock, flags); - - /* - * Data or dataless packet? Dataless frames contains only the - * TTP_HEADER. - */ - if (skb->len > 1) { - /* - * We don't remove the TTP header, since we must preserve the - * more bit, so the defragment routing knows what to do - */ - skb_queue_tail(&self->rx_queue, skb); - } else { - /* Dataless flowdata TTP-PDU */ - dev_kfree_skb(skb); - } - - - /* Push data to the higher layer. - * We do it synchronously because running the todo timer for each - * receive packet would be too much overhead and latency. - * By passing control to the higher layer, we run the risk that - * it may take time or grab a lock. Most often, the higher layer - * will only put packet in a queue. - * Anyway, packets are only dripping through the IrDA, so we can - * have time before the next packet. - * Further, we are run from NET_BH, so the worse that can happen is - * us missing the optimal time to send back the PF bit in LAP. - * Jean II */ - irttp_run_rx_queue(self); - - /* We now give credits to peer in irttp_run_rx_queue(). - * We need to send credit *NOW*, otherwise we are going - * to miss the next Tx window. The todo timer may take - * a while before it's run... - Jean II */ - - /* - * If the peer device has given us some credits and we didn't have - * anyone from before, then we need to shedule the tx queue. - * We need to do that because our Tx have stopped (so we may not - * get any LAP flow indication) and the user may be stopped as - * well. - Jean II - */ - if (self->send_credit == n) { - /* Restart pushing stuff to LAP */ - irttp_run_tx_queue(self); - /* Note : we don't want to schedule the todo timer - * because it has horrible latency. No tasklets - * because the tasklet API is broken. - Jean II */ - } - - return 0; -} - -/* - * Function irttp_status_indication (self, reason) - * - * Status_indication, just pass to the higher layer... - * - */ -static void irttp_status_indication(void *instance, - LINK_STATUS link, LOCK_STATUS lock) -{ - struct tsap_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - - /* Check if client has already closed the TSAP and gone away */ - if (self->close_pend) - return; - - /* - * Inform service user if he has requested it - */ - if (self->notify.status_indication != NULL) - self->notify.status_indication(self->notify.instance, - link, lock); - else - pr_debug("%s(), no handler\n", __func__); -} - -/* - * Function irttp_flow_indication (self, reason) - * - * Flow_indication : IrLAP tells us to send more data. - * - */ -static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) -{ - struct tsap_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - - pr_debug("%s(instance=%p)\n", __func__, self); - - /* We are "polled" directly from LAP, and the LAP want to fill - * its Tx window. We want to do our best to send it data, so that - * we maximise the window. On the other hand, we want to limit the - * amount of work here so that LAP doesn't hang forever waiting - * for packets. - Jean II */ - - /* Try to send some packets. Currently, LAP calls us every time - * there is one free slot, so we will send only one packet. - * This allow the scheduler to do its round robin - Jean II */ - irttp_run_tx_queue(self); - - /* Note regarding the interraction with higher layer. - * irttp_run_tx_queue() may call the client when its queue - * start to empty, via notify.flow_indication(). Initially. - * I wanted this to happen in a tasklet, to avoid client - * grabbing the CPU, but we can't use tasklets safely. And timer - * is definitely too slow. - * This will happen only once per LAP window, and usually at - * the third packet (unless window is smaller). LAP is still - * doing mtt and sending first packet so it's sort of OK - * to do that. Jean II */ - - /* If we need to send disconnect. try to do it now */ - if (self->disconnect_pend) - irttp_start_todo_timer(self, 0); -} - -/* - * Function irttp_flow_request (self, command) - * - * This function could be used by the upper layers to tell IrTTP to stop - * delivering frames if the receive queues are starting to get full, or - * to tell IrTTP to start delivering frames again. - */ -void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow) -{ - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - - switch (flow) { - case FLOW_STOP: - pr_debug("%s(), flow stop\n", __func__); - self->rx_sdu_busy = TRUE; - break; - case FLOW_START: - pr_debug("%s(), flow start\n", __func__); - self->rx_sdu_busy = FALSE; - - /* Client say he can accept more data, try to free our - * queues ASAP - Jean II */ - irttp_run_rx_queue(self); - - break; - default: - pr_debug("%s(), Unknown flow command!\n", __func__); - } -} -EXPORT_SYMBOL(irttp_flow_request); - -/* - * Function irttp_connect_request (self, dtsap_sel, daddr, qos) - * - * Try to connect to remote destination TSAP selector - * - */ -int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, - __u32 saddr, __u32 daddr, - struct qos_info *qos, __u32 max_sdu_size, - struct sk_buff *userdata) -{ - struct sk_buff *tx_skb; - __u8 *frame; - __u8 n; - - pr_debug("%s(), max_sdu_size=%d\n", __func__, max_sdu_size); - - IRDA_ASSERT(self != NULL, return -EBADR;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;); - - if (self->connected) { - if (userdata) - dev_kfree_skb(userdata); - return -EISCONN; - } - - /* Any userdata supplied? */ - if (userdata == NULL) { - tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, - GFP_ATOMIC); - if (!tx_skb) - return -ENOMEM; - - /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER); - } else { - tx_skb = userdata; - /* - * Check that the client has reserved enough space for - * headers - */ - IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, - { dev_kfree_skb(userdata); return -1; }); - } - - /* Initialize connection parameters */ - self->connected = FALSE; - self->avail_credit = 0; - self->rx_max_sdu_size = max_sdu_size; - self->rx_sdu_size = 0; - self->rx_sdu_busy = FALSE; - self->dtsap_sel = dtsap_sel; - - n = self->initial_credit; - - self->remote_credit = 0; - self->send_credit = 0; - - /* - * Give away max 127 credits for now - */ - if (n > 127) { - self->avail_credit = n - 127; - n = 127; - } - - self->remote_credit = n; - - /* SAR enabled? */ - if (max_sdu_size > 0) { - IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), - { dev_kfree_skb(tx_skb); return -1; }); - - /* Insert SAR parameters */ - frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER); - - frame[0] = TTP_PARAMETERS | n; - frame[1] = 0x04; /* Length */ - frame[2] = 0x01; /* MaxSduSize */ - frame[3] = 0x02; /* Value length */ - - put_unaligned(cpu_to_be16((__u16) max_sdu_size), - (__be16 *)(frame+4)); - } else { - /* Insert plain TTP header */ - frame = skb_push(tx_skb, TTP_HEADER); - - /* Insert initial credit in frame */ - frame[0] = n & 0x7f; - } - - /* Connect with IrLMP. No QoS parameters for now */ - return irlmp_connect_request(self->lsap, dtsap_sel, saddr, daddr, qos, - tx_skb); -} -EXPORT_SYMBOL(irttp_connect_request); - -/* - * Function irttp_connect_confirm (handle, qos, skb) - * - * Service user confirms TSAP connection with peer. - * - */ -static void irttp_connect_confirm(void *instance, void *sap, - struct qos_info *qos, __u32 max_seg_size, - __u8 max_header_size, struct sk_buff *skb) -{ - struct tsap_cb *self; - int parameters; - int ret; - __u8 plen; - __u8 n; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - self->max_seg_size = max_seg_size - TTP_HEADER; - self->max_header_size = max_header_size + TTP_HEADER; - - /* - * Check if we have got some QoS parameters back! This should be the - * negotiated QoS for the link. - */ - if (qos) { - pr_debug("IrTTP, Negotiated BAUD_RATE: %02x\n", - qos->baud_rate.bits); - pr_debug("IrTTP, Negotiated BAUD_RATE: %d bps.\n", - qos->baud_rate.value); - } - - n = skb->data[0] & 0x7f; - - pr_debug("%s(), Initial send_credit=%d\n", __func__, n); - - self->send_credit = n; - self->tx_max_sdu_size = 0; - self->connected = TRUE; - - parameters = skb->data[0] & 0x80; - - IRDA_ASSERT(skb->len >= TTP_HEADER, return;); - skb_pull(skb, TTP_HEADER); - - if (parameters) { - plen = skb->data[0]; - - ret = irda_param_extract_all(self, skb->data+1, - IRDA_MIN(skb->len-1, plen), - ¶m_info); - - /* Any errors in the parameter list? */ - if (ret < 0) { - net_warn_ratelimited("%s: error extracting parameters\n", - __func__); - dev_kfree_skb(skb); - - /* Do not accept this connection attempt */ - return; - } - /* Remove parameters */ - skb_pull(skb, IRDA_MIN(skb->len, plen+1)); - } - - pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__, - self->send_credit, self->avail_credit, self->remote_credit); - - pr_debug("%s(), MaxSduSize=%d\n", __func__, - self->tx_max_sdu_size); - - if (self->notify.connect_confirm) { - self->notify.connect_confirm(self->notify.instance, self, qos, - self->tx_max_sdu_size, - self->max_header_size, skb); - } else - dev_kfree_skb(skb); -} - -/* - * Function irttp_connect_indication (handle, skb) - * - * Some other device is connecting to this TSAP - * - */ -static void irttp_connect_indication(void *instance, void *sap, - struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, - struct sk_buff *skb) -{ - struct tsap_cb *self; - struct lsap_cb *lsap; - int parameters; - int ret; - __u8 plen; - __u8 n; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - IRDA_ASSERT(skb != NULL, return;); - - lsap = sap; - - self->max_seg_size = max_seg_size - TTP_HEADER; - self->max_header_size = max_header_size+TTP_HEADER; - - pr_debug("%s(), TSAP sel=%02x\n", __func__, self->stsap_sel); - - /* Need to update dtsap_sel if its equal to LSAP_ANY */ - self->dtsap_sel = lsap->dlsap_sel; - - n = skb->data[0] & 0x7f; - - self->send_credit = n; - self->tx_max_sdu_size = 0; - - parameters = skb->data[0] & 0x80; - - IRDA_ASSERT(skb->len >= TTP_HEADER, return;); - skb_pull(skb, TTP_HEADER); - - if (parameters) { - plen = skb->data[0]; - - ret = irda_param_extract_all(self, skb->data+1, - IRDA_MIN(skb->len-1, plen), - ¶m_info); - - /* Any errors in the parameter list? */ - if (ret < 0) { - net_warn_ratelimited("%s: error extracting parameters\n", - __func__); - dev_kfree_skb(skb); - - /* Do not accept this connection attempt */ - return; - } - - /* Remove parameters */ - skb_pull(skb, IRDA_MIN(skb->len, plen+1)); - } - - if (self->notify.connect_indication) { - self->notify.connect_indication(self->notify.instance, self, - qos, self->tx_max_sdu_size, - self->max_header_size, skb); - } else - dev_kfree_skb(skb); -} - -/* - * Function irttp_connect_response (handle, userdata) - * - * Service user is accepting the connection, just pass it down to - * IrLMP! - * - */ -int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, - struct sk_buff *userdata) -{ - struct sk_buff *tx_skb; - __u8 *frame; - int ret; - __u8 n; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - - pr_debug("%s(), Source TSAP selector=%02x\n", __func__, - self->stsap_sel); - - /* Any userdata supplied? */ - if (userdata == NULL) { - tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, - GFP_ATOMIC); - if (!tx_skb) - return -ENOMEM; - - /* Reserve space for MUX_CONTROL and LAP header */ - skb_reserve(tx_skb, TTP_MAX_HEADER + TTP_SAR_HEADER); - } else { - tx_skb = userdata; - /* - * Check that the client has reserved enough space for - * headers - */ - IRDA_ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, - { dev_kfree_skb(userdata); return -1; }); - } - - self->avail_credit = 0; - self->remote_credit = 0; - self->rx_max_sdu_size = max_sdu_size; - self->rx_sdu_size = 0; - self->rx_sdu_busy = FALSE; - - n = self->initial_credit; - - /* Frame has only space for max 127 credits (7 bits) */ - if (n > 127) { - self->avail_credit = n - 127; - n = 127; - } - - self->remote_credit = n; - self->connected = TRUE; - - /* SAR enabled? */ - if (max_sdu_size > 0) { - IRDA_ASSERT(skb_headroom(tx_skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), - { dev_kfree_skb(tx_skb); return -1; }); - - /* Insert TTP header with SAR parameters */ - frame = skb_push(tx_skb, TTP_HEADER + TTP_SAR_HEADER); - - frame[0] = TTP_PARAMETERS | n; - frame[1] = 0x04; /* Length */ - - /* irda_param_insert(self, IRTTP_MAX_SDU_SIZE, frame+1, */ -/* TTP_SAR_HEADER, ¶m_info) */ - - frame[2] = 0x01; /* MaxSduSize */ - frame[3] = 0x02; /* Value length */ - - put_unaligned(cpu_to_be16((__u16) max_sdu_size), - (__be16 *)(frame+4)); - } else { - /* Insert TTP header */ - frame = skb_push(tx_skb, TTP_HEADER); - - frame[0] = n & 0x7f; - } - - ret = irlmp_connect_response(self->lsap, tx_skb); - - return ret; -} -EXPORT_SYMBOL(irttp_connect_response); - -/* - * Function irttp_dup (self, instance) - * - * Duplicate TSAP, can be used by servers to confirm a connection on a - * new TSAP so it can keep listening on the old one. - */ -struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) -{ - struct tsap_cb *new; - unsigned long flags; - - /* Protect our access to the old tsap instance */ - spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags); - - /* Find the old instance */ - if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) { - pr_debug("%s(), unable to find TSAP\n", __func__); - spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); - return NULL; - } - - /* Allocate a new instance */ - new = kmemdup(orig, sizeof(struct tsap_cb), GFP_ATOMIC); - if (!new) { - pr_debug("%s(), unable to kmalloc\n", __func__); - spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); - return NULL; - } - spin_lock_init(&new->lock); - - /* We don't need the old instance any more */ - spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); - - /* Try to dup the LSAP (may fail if we were too slow) */ - new->lsap = irlmp_dup(orig->lsap, new); - if (!new->lsap) { - pr_debug("%s(), dup failed!\n", __func__); - kfree(new); - return NULL; - } - - /* Not everything should be copied */ - new->notify.instance = instance; - - /* Initialize internal objects */ - irttp_init_tsap(new); - - /* This is locked */ - hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (long) new, NULL); - - return new; -} -EXPORT_SYMBOL(irttp_dup); - -/* - * Function irttp_disconnect_request (self) - * - * Close this connection please! If priority is high, the queued data - * segments, if any, will be deallocated first - * - */ -int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, - int priority) -{ - int ret; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - - /* Already disconnected? */ - if (!self->connected) { - pr_debug("%s(), already disconnected!\n", __func__); - if (userdata) - dev_kfree_skb(userdata); - return -1; - } - - /* Disconnect already pending ? - * We need to use an atomic operation to prevent reentry. This - * function may be called from various context, like user, timer - * for following a disconnect_indication() (i.e. net_bh). - * Jean II */ - if (test_and_set_bit(0, &self->disconnect_pend)) { - pr_debug("%s(), disconnect already pending\n", - __func__); - if (userdata) - dev_kfree_skb(userdata); - - /* Try to make some progress */ - irttp_run_tx_queue(self); - return -1; - } - - /* - * Check if there is still data segments in the transmit queue - */ - if (!skb_queue_empty(&self->tx_queue)) { - if (priority == P_HIGH) { - /* - * No need to send the queued data, if we are - * disconnecting right now since the data will - * not have any usable connection to be sent on - */ - pr_debug("%s(): High priority!!()\n", __func__); - irttp_flush_queues(self); - } else if (priority == P_NORMAL) { - /* - * Must delay disconnect until after all data segments - * have been sent and the tx_queue is empty - */ - /* We'll reuse this one later for the disconnect */ - self->disconnect_skb = userdata; /* May be NULL */ - - irttp_run_tx_queue(self); - - irttp_start_todo_timer(self, HZ/10); - return -1; - } - } - /* Note : we don't need to check if self->rx_queue is full and the - * state of self->rx_sdu_busy because the disconnect response will - * be sent at the LMP level (so even if the peer has its Tx queue - * full of data). - Jean II */ - - pr_debug("%s(), Disconnecting ...\n", __func__); - self->connected = FALSE; - - if (!userdata) { - struct sk_buff *tx_skb; - tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); - if (!tx_skb) - return -ENOMEM; - - /* - * Reserve space for MUX and LAP header - */ - skb_reserve(tx_skb, LMP_MAX_HEADER); - - userdata = tx_skb; - } - ret = irlmp_disconnect_request(self->lsap, userdata); - - /* The disconnect is no longer pending */ - clear_bit(0, &self->disconnect_pend); /* FALSE */ - - return ret; -} -EXPORT_SYMBOL(irttp_disconnect_request); - -/* - * Function irttp_disconnect_indication (self, reason) - * - * Disconnect indication, TSAP disconnected by peer? - * - */ -static void irttp_disconnect_indication(void *instance, void *sap, - LM_REASON reason, struct sk_buff *skb) -{ - struct tsap_cb *self; - - self = instance; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - - /* Prevent higher layer to send more data */ - self->connected = FALSE; - - /* Check if client has already tried to close the TSAP */ - if (self->close_pend) { - /* In this case, the higher layer is probably gone. Don't - * bother it and clean up the remains - Jean II */ - if (skb) - dev_kfree_skb(skb); - irttp_close_tsap(self); - return; - } - - /* If we are here, we assume that is the higher layer is still - * waiting for the disconnect notification and able to process it, - * even if he tried to disconnect. Otherwise, it would have already - * attempted to close the tsap and self->close_pend would be TRUE. - * Jean II */ - - /* No need to notify the client if has already tried to disconnect */ - if (self->notify.disconnect_indication) - self->notify.disconnect_indication(self->notify.instance, self, - reason, skb); - else - if (skb) - dev_kfree_skb(skb); -} - -/* - * Function irttp_do_data_indication (self, skb) - * - * Try to deliver reassembled skb to layer above, and requeue it if that - * for some reason should fail. We mark rx sdu as busy to apply back - * pressure is necessary. - */ -static void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb) -{ - int err; - - /* Check if client has already closed the TSAP and gone away */ - if (self->close_pend) { - dev_kfree_skb(skb); - return; - } - - err = self->notify.data_indication(self->notify.instance, self, skb); - - /* Usually the layer above will notify that it's input queue is - * starting to get filled by using the flow request, but this may - * be difficult, so it can instead just refuse to eat it and just - * give an error back - */ - if (err) { - pr_debug("%s() requeueing skb!\n", __func__); - - /* Make sure we take a break */ - self->rx_sdu_busy = TRUE; - - /* Need to push the header in again */ - skb_push(skb, TTP_HEADER); - skb->data[0] = 0x00; /* Make sure MORE bit is cleared */ - - /* Put skb back on queue */ - skb_queue_head(&self->rx_queue, skb); - } -} - -/* - * Function irttp_run_rx_queue (self) - * - * Check if we have any frames to be transmitted, or if we have any - * available credit to give away. - */ -static void irttp_run_rx_queue(struct tsap_cb *self) -{ - struct sk_buff *skb; - int more = 0; - - pr_debug("%s() send=%d,avail=%d,remote=%d\n", __func__, - self->send_credit, self->avail_credit, self->remote_credit); - - /* Get exclusive access to the rx queue, otherwise don't touch it */ - if (irda_lock(&self->rx_queue_lock) == FALSE) - return; - - /* - * Reassemble all frames in receive queue and deliver them - */ - while (!self->rx_sdu_busy && (skb = skb_dequeue(&self->rx_queue))) { - /* This bit will tell us if it's the last fragment or not */ - more = skb->data[0] & 0x80; - - /* Remove TTP header */ - skb_pull(skb, TTP_HEADER); - - /* Add the length of the remaining data */ - self->rx_sdu_size += skb->len; - - /* - * If SAR is disabled, or user has requested no reassembly - * of received fragments then we just deliver them - * immediately. This can be requested by clients that - * implements byte streams without any message boundaries - */ - if (self->rx_max_sdu_size == TTP_SAR_DISABLE) { - irttp_do_data_indication(self, skb); - self->rx_sdu_size = 0; - - continue; - } - - /* Check if this is a fragment, and not the last fragment */ - if (more) { - /* - * Queue the fragment if we still are within the - * limits of the maximum size of the rx_sdu - */ - if (self->rx_sdu_size <= self->rx_max_sdu_size) { - pr_debug("%s(), queueing frag\n", - __func__); - skb_queue_tail(&self->rx_fragments, skb); - } else { - /* Free the part of the SDU that is too big */ - dev_kfree_skb(skb); - } - continue; - } - /* - * This is the last fragment, so time to reassemble! - */ - if ((self->rx_sdu_size <= self->rx_max_sdu_size) || - (self->rx_max_sdu_size == TTP_SAR_UNBOUND)) { - /* - * A little optimizing. Only queue the fragment if - * there are other fragments. Since if this is the - * last and only fragment, there is no need to - * reassemble :-) - */ - if (!skb_queue_empty(&self->rx_fragments)) { - skb_queue_tail(&self->rx_fragments, - skb); - - skb = irttp_reassemble_skb(self); - } - - /* Now we can deliver the reassembled skb */ - irttp_do_data_indication(self, skb); - } else { - pr_debug("%s(), Truncated frame\n", __func__); - - /* Free the part of the SDU that is too big */ - dev_kfree_skb(skb); - - /* Deliver only the valid but truncated part of SDU */ - skb = irttp_reassemble_skb(self); - - irttp_do_data_indication(self, skb); - } - self->rx_sdu_size = 0; - } - - /* - * It's not trivial to keep track of how many credits are available - * by incrementing at each packet, because delivery may fail - * (irttp_do_data_indication() may requeue the frame) and because - * we need to take care of fragmentation. - * We want the other side to send up to initial_credit packets. - * We have some frames in our queues, and we have already allowed it - * to send remote_credit. - * No need to spinlock, write is atomic and self correcting... - * Jean II - */ - self->avail_credit = (self->initial_credit - - (self->remote_credit + - skb_queue_len(&self->rx_queue) + - skb_queue_len(&self->rx_fragments))); - - /* Do we have too much credits to send to peer ? */ - if ((self->remote_credit <= TTP_RX_MIN_CREDIT) && - (self->avail_credit > 0)) { - /* Send explicit credit frame */ - irttp_give_credit(self); - /* Note : do *NOT* check if tx_queue is non-empty, that - * will produce deadlocks. I repeat : send a credit frame - * even if we have something to send in our Tx queue. - * If we have credits, it means that our Tx queue is blocked. - * - * Let's suppose the peer can't keep up with our Tx. He will - * flow control us by not sending us any credits, and we - * will stop Tx and start accumulating credits here. - * Up to the point where the peer will stop its Tx queue, - * for lack of credits. - * Let's assume the peer application is single threaded. - * It will block on Tx and never consume any Rx buffer. - * Deadlock. Guaranteed. - Jean II - */ - } - - /* Reset lock */ - self->rx_queue_lock = 0; -} - -#ifdef CONFIG_PROC_FS -struct irttp_iter_state { - int id; -}; - -static void *irttp_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct irttp_iter_state *iter = seq->private; - struct tsap_cb *self; - - /* Protect our access to the tsap list */ - spin_lock_irq(&irttp->tsaps->hb_spinlock); - iter->id = 0; - - for (self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps); - self != NULL; - self = (struct tsap_cb *) hashbin_get_next(irttp->tsaps)) { - if (iter->id == *pos) - break; - ++iter->id; - } - - return self; -} - -static void *irttp_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct irttp_iter_state *iter = seq->private; - - ++*pos; - ++iter->id; - return (void *) hashbin_get_next(irttp->tsaps); -} - -static void irttp_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_irq(&irttp->tsaps->hb_spinlock); -} - -static int irttp_seq_show(struct seq_file *seq, void *v) -{ - const struct irttp_iter_state *iter = seq->private; - const struct tsap_cb *self = v; - - seq_printf(seq, "TSAP %d, ", iter->id); - seq_printf(seq, "stsap_sel: %02x, ", - self->stsap_sel); - seq_printf(seq, "dtsap_sel: %02x\n", - self->dtsap_sel); - seq_printf(seq, " connected: %s, ", - self->connected ? "TRUE" : "FALSE"); - seq_printf(seq, "avail credit: %d, ", - self->avail_credit); - seq_printf(seq, "remote credit: %d, ", - self->remote_credit); - seq_printf(seq, "send credit: %d\n", - self->send_credit); - seq_printf(seq, " tx packets: %lu, ", - self->stats.tx_packets); - seq_printf(seq, "rx packets: %lu, ", - self->stats.rx_packets); - seq_printf(seq, "tx_queue len: %u ", - skb_queue_len(&self->tx_queue)); - seq_printf(seq, "rx_queue len: %u\n", - skb_queue_len(&self->rx_queue)); - seq_printf(seq, " tx_sdu_busy: %s, ", - self->tx_sdu_busy ? "TRUE" : "FALSE"); - seq_printf(seq, "rx_sdu_busy: %s\n", - self->rx_sdu_busy ? "TRUE" : "FALSE"); - seq_printf(seq, " max_seg_size: %u, ", - self->max_seg_size); - seq_printf(seq, "tx_max_sdu_size: %u, ", - self->tx_max_sdu_size); - seq_printf(seq, "rx_max_sdu_size: %u\n", - self->rx_max_sdu_size); - - seq_printf(seq, " Used by (%s)\n\n", - self->notify.name); - return 0; -} - -static const struct seq_operations irttp_seq_ops = { - .start = irttp_seq_start, - .next = irttp_seq_next, - .stop = irttp_seq_stop, - .show = irttp_seq_show, -}; - -static int irttp_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_private(file, &irttp_seq_ops, - sizeof(struct irttp_iter_state)); -} - -const struct file_operations irttp_seq_fops = { - .owner = THIS_MODULE, - .open = irttp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - -#endif /* PROC_FS */ diff --git a/drivers/staging/irda/net/parameters.c b/drivers/staging/irda/net/parameters.c deleted file mode 100644 index 16ce32ffe004..000000000000 --- a/drivers/staging/irda/net/parameters.c +++ /dev/null @@ -1,584 +0,0 @@ -/********************************************************************* - * - * Filename: parameters.c - * Version: 1.0 - * Description: A more general way to handle (pi,pl,pv) parameters - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Jun 7 10:25:11 1999 - * Modified at: Sun Jan 30 14:08:39 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved. - * - * 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, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/types.h> -#include <linux/module.h> - -#include <asm/unaligned.h> -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/parameters.h> - -static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func); -static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func); -static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func); -static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func); - -static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func); -static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func); - -static int irda_param_unpack(__u8 *buf, char *fmt, ...); - -/* Parameter value call table. Must match PV_TYPE */ -static const PV_HANDLER pv_extract_table[] = { - irda_extract_integer, /* Handler for any length integers */ - irda_extract_integer, /* Handler for 8 bits integers */ - irda_extract_integer, /* Handler for 16 bits integers */ - irda_extract_string, /* Handler for strings */ - irda_extract_integer, /* Handler for 32 bits integers */ - irda_extract_octseq, /* Handler for octet sequences */ - irda_extract_no_value /* Handler for no value parameters */ -}; - -static const PV_HANDLER pv_insert_table[] = { - irda_insert_integer, /* Handler for any length integers */ - irda_insert_integer, /* Handler for 8 bits integers */ - irda_insert_integer, /* Handler for 16 bits integers */ - NULL, /* Handler for strings */ - irda_insert_integer, /* Handler for 32 bits integers */ - NULL, /* Handler for octet sequences */ - irda_insert_no_value /* Handler for no value parameters */ -}; - -/* - * Function irda_insert_no_value (self, buf, len, pi, type, func) - */ -static int irda_insert_no_value(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func) -{ - irda_param_t p; - int ret; - - p.pi = pi; - p.pl = 0; - - /* Call handler for this parameter */ - ret = (*func)(self, &p, PV_GET); - - /* Extract values anyway, since handler may need them */ - irda_param_pack(buf, "bb", p.pi, p.pl); - - if (ret < 0) - return ret; - - return 2; /* Inserted pl+2 bytes */ -} - -/* - * Function irda_extract_no_value (self, buf, len, type, func) - * - * Extracts a parameter without a pv field (pl=0) - * - */ -static int irda_extract_no_value(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func) -{ - irda_param_t p; - int ret; - - /* Extract values anyway, since handler may need them */ - irda_param_unpack(buf, "bb", &p.pi, &p.pl); - - /* Call handler for this parameter */ - ret = (*func)(self, &p, PV_PUT); - - if (ret < 0) - return ret; - - return 2; /* Extracted pl+2 bytes */ -} - -/* - * Function irda_insert_integer (self, buf, len, pi, type, func) - */ -static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func) -{ - irda_param_t p; - int n = 0; - int err; - - p.pi = pi; /* In case handler needs to know */ - p.pl = type & PV_MASK; /* The integer type codes the length as well */ - p.pv.i = 0; /* Clear value */ - - /* Call handler for this parameter */ - err = (*func)(self, &p, PV_GET); - if (err < 0) - return err; - - /* - * If parameter length is still 0, then (1) this is an any length - * integer, and (2) the handler function does not care which length - * we choose to use, so we pick the one the gives the fewest bytes. - */ - if (p.pl == 0) { - if (p.pv.i < 0xff) { - pr_debug("%s(), using 1 byte\n", __func__); - p.pl = 1; - } else if (p.pv.i < 0xffff) { - pr_debug("%s(), using 2 bytes\n", __func__); - p.pl = 2; - } else { - pr_debug("%s(), using 4 bytes\n", __func__); - p.pl = 4; /* Default length */ - } - } - /* Check if buffer is long enough for insertion */ - if (len < (2+p.pl)) { - net_warn_ratelimited("%s: buffer too short for insertion!\n", - __func__); - return -1; - } - pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__, - p.pi, p.pl, p.pv.i); - switch (p.pl) { - case 1: - n += irda_param_pack(buf, "bbb", p.pi, p.pl, (__u8) p.pv.i); - break; - case 2: - if (type & PV_BIG_ENDIAN) - p.pv.i = cpu_to_be16((__u16) p.pv.i); - else - p.pv.i = cpu_to_le16((__u16) p.pv.i); - n += irda_param_pack(buf, "bbs", p.pi, p.pl, (__u16) p.pv.i); - break; - case 4: - if (type & PV_BIG_ENDIAN) - cpu_to_be32s(&p.pv.i); - else - cpu_to_le32s(&p.pv.i); - n += irda_param_pack(buf, "bbi", p.pi, p.pl, p.pv.i); - - break; - default: - net_warn_ratelimited("%s: length %d not supported\n", - __func__, p.pl); - /* Skip parameter */ - return -1; - } - - return p.pl+2; /* Inserted pl+2 bytes */ -} - -/* - * Function irda_extract integer (self, buf, len, pi, type, func) - * - * Extract a possibly variable length integer from buffer, and call - * handler for processing of the parameter - */ -static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func) -{ - irda_param_t p; - int n = 0; - int extract_len; /* Real length we extract */ - int err; - - p.pi = pi; /* In case handler needs to know */ - p.pl = buf[1]; /* Extract length of value */ - p.pv.i = 0; /* Clear value */ - extract_len = p.pl; /* Default : extract all */ - - /* Check if buffer is long enough for parsing */ - if (len < (2+p.pl)) { - net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", - __func__, p.pl, len); - return -1; - } - - /* - * Check that the integer length is what we expect it to be. If the - * handler want a 16 bits integer then a 32 bits is not good enough - * PV_INTEGER means that the handler is flexible. - */ - if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) { - net_err_ratelimited("%s: invalid parameter length! Expected %d bytes, but value had %d bytes!\n", - __func__, type & PV_MASK, p.pl); - - /* Most parameters are bit/byte fields or little endian, - * so it's ok to only extract a subset of it (the subset - * that the handler expect). This is necessary, as some - * broken implementations seems to add extra undefined bits. - * If the parameter is shorter than we expect or is big - * endian, we can't play those tricks. Jean II */ - if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) { - /* Skip parameter */ - return p.pl+2; - } else { - /* Extract subset of it, fallthrough */ - extract_len = type & PV_MASK; - } - } - - - switch (extract_len) { - case 1: - n += irda_param_unpack(buf+2, "b", &p.pv.i); - break; - case 2: - n += irda_param_unpack(buf+2, "s", &p.pv.i); - if (type & PV_BIG_ENDIAN) - p.pv.i = be16_to_cpu((__u16) p.pv.i); - else - p.pv.i = le16_to_cpu((__u16) p.pv.i); - break; - case 4: - n += irda_param_unpack(buf+2, "i", &p.pv.i); - if (type & PV_BIG_ENDIAN) - be32_to_cpus(&p.pv.i); - else - le32_to_cpus(&p.pv.i); - break; - default: - net_warn_ratelimited("%s: length %d not supported\n", - __func__, p.pl); - - /* Skip parameter */ - return p.pl+2; - } - - pr_debug("%s(), pi=%#x, pl=%d, pi=%d\n", __func__, - p.pi, p.pl, p.pv.i); - /* Call handler for this parameter */ - err = (*func)(self, &p, PV_PUT); - if (err < 0) - return err; - - return p.pl+2; /* Extracted pl+2 bytes */ -} - -/* - * Function irda_extract_string (self, buf, len, type, func) - */ -static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func) -{ - char str[33]; - irda_param_t p; - int err; - - p.pi = pi; /* In case handler needs to know */ - p.pl = buf[1]; /* Extract length of value */ - if (p.pl > 32) - p.pl = 32; - - pr_debug("%s(), pi=%#x, pl=%d\n", __func__, - p.pi, p.pl); - - /* Check if buffer is long enough for parsing */ - if (len < (2+p.pl)) { - net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", - __func__, p.pl, len); - return -1; - } - - /* Should be safe to copy string like this since we have already - * checked that the buffer is long enough */ - strncpy(str, buf+2, p.pl); - - pr_debug("%s(), str=0x%02x 0x%02x\n", - __func__, (__u8)str[0], (__u8)str[1]); - - /* Null terminate string */ - str[p.pl] = '\0'; - - p.pv.c = str; /* Handler will need to take a copy */ - - /* Call handler for this parameter */ - err = (*func)(self, &p, PV_PUT); - if (err < 0) - return err; - - return p.pl+2; /* Extracted pl+2 bytes */ -} - -/* - * Function irda_extract_octseq (self, buf, len, type, func) - */ -static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, - PV_TYPE type, PI_HANDLER func) -{ - irda_param_t p; - - p.pi = pi; /* In case handler needs to know */ - p.pl = buf[1]; /* Extract length of value */ - - /* Check if buffer is long enough for parsing */ - if (len < (2+p.pl)) { - net_warn_ratelimited("%s: buffer too short for parsing! Need %d bytes, but len is only %d\n", - __func__, p.pl, len); - return -1; - } - - pr_debug("%s(), not impl\n", __func__); - - return p.pl+2; /* Extracted pl+2 bytes */ -} - -/* - * Function irda_param_pack (skb, fmt, ...) - * - * Format: - * 'i' = 32 bits integer - * 's' = string - * - */ -int irda_param_pack(__u8 *buf, char *fmt, ...) -{ - irda_pv_t arg; - va_list args; - char *p; - int n = 0; - - va_start(args, fmt); - - for (p = fmt; *p != '\0'; p++) { - switch (*p) { - case 'b': /* 8 bits unsigned byte */ - buf[n++] = (__u8)va_arg(args, int); - break; - case 's': /* 16 bits unsigned short */ - arg.i = (__u16)va_arg(args, int); - put_unaligned((__u16)arg.i, (__u16 *)(buf+n)); n+=2; - break; - case 'i': /* 32 bits unsigned integer */ - arg.i = va_arg(args, __u32); - put_unaligned(arg.i, (__u32 *)(buf+n)); n+=4; - break; -#if 0 - case 'c': /* \0 terminated string */ - arg.c = va_arg(args, char *); - strcpy(buf+n, arg.c); - n += strlen(arg.c) + 1; - break; -#endif - default: - va_end(args); - return -1; - } - } - va_end(args); - - return 0; -} -EXPORT_SYMBOL(irda_param_pack); - -/* - * Function irda_param_unpack (skb, fmt, ...) - */ -static int irda_param_unpack(__u8 *buf, char *fmt, ...) -{ - irda_pv_t arg; - va_list args; - char *p; - int n = 0; - - va_start(args, fmt); - - for (p = fmt; *p != '\0'; p++) { - switch (*p) { - case 'b': /* 8 bits byte */ - arg.ip = va_arg(args, __u32 *); - *arg.ip = buf[n++]; - break; - case 's': /* 16 bits short */ - arg.ip = va_arg(args, __u32 *); - *arg.ip = get_unaligned((__u16 *)(buf+n)); n+=2; - break; - case 'i': /* 32 bits unsigned integer */ - arg.ip = va_arg(args, __u32 *); - *arg.ip = get_unaligned((__u32 *)(buf+n)); n+=4; - break; -#if 0 - case 'c': /* \0 terminated string */ - arg.c = va_arg(args, char *); - strcpy(arg.c, buf+n); - n += strlen(arg.c) + 1; - break; -#endif - default: - va_end(args); - return -1; - } - - } - va_end(args); - - return 0; -} - -/* - * Function irda_param_insert (self, pi, buf, len, info) - * - * Insert the specified parameter (pi) into buffer. Returns number of - * bytes inserted - */ -int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, - pi_param_info_t *info) -{ - const pi_minor_info_t *pi_minor_info; - __u8 pi_minor; - __u8 pi_major; - int type; - int ret = -1; - int n = 0; - - IRDA_ASSERT(buf != NULL, return ret;); - IRDA_ASSERT(info != NULL, return ret;); - - pi_minor = pi & info->pi_mask; - pi_major = pi >> info->pi_major_offset; - - /* Check if the identifier value (pi) is valid */ - if ((pi_major > info->len-1) || - (pi_minor > info->tables[pi_major].len-1)) - { - pr_debug("%s(), no handler for parameter=0x%02x\n", - __func__, pi); - - /* Skip this parameter */ - return -1; - } - - /* Lookup the info on how to parse this parameter */ - pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor]; - - /* Find expected data type for this parameter identifier (pi)*/ - type = pi_minor_info->type; - - /* Check if handler has been implemented */ - if (!pi_minor_info->func) { - net_info_ratelimited("%s: no handler for pi=%#x\n", - __func__, pi); - /* Skip this parameter */ - return -1; - } - - /* Insert parameter value */ - ret = (*pv_insert_table[type & PV_MASK])(self, buf+n, len, pi, type, - pi_minor_info->func); - return ret; -} -EXPORT_SYMBOL(irda_param_insert); - -/* - * Function irda_param_extract (self, buf, len, info) - * - * Parse all parameters. If len is correct, then everything should be - * safe. Returns the number of bytes that was parsed - * - */ -static int irda_param_extract(void *self, __u8 *buf, int len, - pi_param_info_t *info) -{ - const pi_minor_info_t *pi_minor_info; - __u8 pi_minor; - __u8 pi_major; - int type; - int ret = -1; - int n = 0; - - IRDA_ASSERT(buf != NULL, return ret;); - IRDA_ASSERT(info != NULL, return ret;); - - pi_minor = buf[n] & info->pi_mask; - pi_major = buf[n] >> info->pi_major_offset; - - /* Check if the identifier value (pi) is valid */ - if ((pi_major > info->len-1) || - (pi_minor > info->tables[pi_major].len-1)) - { - pr_debug("%s(), no handler for parameter=0x%02x\n", - __func__, buf[0]); - - /* Skip this parameter */ - return 2 + buf[n + 1]; /* Continue */ - } - - /* Lookup the info on how to parse this parameter */ - pi_minor_info = &info->tables[pi_major].pi_minor_call_table[pi_minor]; - - /* Find expected data type for this parameter identifier (pi)*/ - type = pi_minor_info->type; - - pr_debug("%s(), pi=[%d,%d], type=%d\n", __func__, - pi_major, pi_minor, type); - - /* Check if handler has been implemented */ - if (!pi_minor_info->func) { - net_info_ratelimited("%s: no handler for pi=%#x\n", - __func__, buf[n]); - /* Skip this parameter */ - return 2 + buf[n + 1]; /* Continue */ - } - - /* Parse parameter value */ - ret = (*pv_extract_table[type & PV_MASK])(self, buf+n, len, buf[n], - type, pi_minor_info->func); - return ret; -} - -/* - * Function irda_param_extract_all (self, buf, len, info) - * - * Parse all parameters. If len is correct, then everything should be - * safe. Returns the number of bytes that was parsed - * - */ -int irda_param_extract_all(void *self, __u8 *buf, int len, - pi_param_info_t *info) -{ - int ret = -1; - int n = 0; - - IRDA_ASSERT(buf != NULL, return ret;); - IRDA_ASSERT(info != NULL, return ret;); - - /* - * Parse all parameters. Each parameter must be at least two bytes - * long or else there is no point in trying to parse it - */ - while (len > 2) { - ret = irda_param_extract(self, buf+n, len, info); - if (ret < 0) - return ret; - - n += ret; - len -= ret; - } - return n; -} -EXPORT_SYMBOL(irda_param_extract_all); diff --git a/drivers/staging/irda/net/qos.c b/drivers/staging/irda/net/qos.c deleted file mode 100644 index 25ba8509ad3e..000000000000 --- a/drivers/staging/irda/net/qos.c +++ /dev/null @@ -1,771 +0,0 @@ -/********************************************************************* - * - * Filename: qos.c - * Version: 1.0 - * Description: IrLAP QoS parameter negotiation - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Tue Sep 9 00:00:26 1997 - * Modified at: Sun Jan 30 14:29:16 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - * - ********************************************************************/ - -#include <linux/export.h> - -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/parameters.h> -#include <net/irda/qos.h> -#include <net/irda/irlap.h> -#include <net/irda/irlap_frame.h> - -/* - * Maximum values of the baud rate we negotiate with the other end. - * Most often, you don't have to change that, because Linux-IrDA will - * use the maximum offered by the link layer, which usually works fine. - * In some very rare cases, you may want to limit it to lower speeds... - */ -int sysctl_max_baud_rate = 16000000; -/* - * Maximum value of the lap disconnect timer we negotiate with the other end. - * Most often, the value below represent the best compromise, but some user - * may want to keep the LAP alive longer or shorter in case of link failure. - * Remember that the threshold time (early warning) is fixed to 3s... - */ -int sysctl_max_noreply_time = 12; -/* - * Minimum turn time to be applied before transmitting to the peer. - * Nonzero values (usec) are used as lower limit to the per-connection - * mtt value which was announced by the other end during negotiation. - * Might be helpful if the peer device provides too short mtt. - * Default is 10us which means using the unmodified value given by the - * peer except if it's 0 (0 is likely a bug in the other stack). - */ -unsigned int sysctl_min_tx_turn_time = 10; -/* - * Maximum data size to be used in transmission in payload of LAP frame. - * There is a bit of confusion in the IrDA spec : - * The LAP spec defines the payload of a LAP frame (I field) to be - * 2048 bytes max (IrLAP 1.1, chapt 6.6.5, p40). - * On the other hand, the PHY mention frames of 2048 bytes max (IrPHY - * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header - * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP - * payload), that's only 2042 bytes. Oups ! - * My nsc-ircc hardware has troubles receiving 2048 bytes frames at 4 Mb/s, - * so adjust to 2042... I don't know if this bug applies only for 2048 - * bytes frames or all negotiated frame sizes, but you can use the sysctl - * to play with this value anyway. - * Jean II */ -unsigned int sysctl_max_tx_data_size = 2042; -/* - * Maximum transmit window, i.e. number of LAP frames between turn-around. - * This allow to override what the peer told us. Some peers are buggy and - * don't always support what they tell us. - * Jean II */ -unsigned int sysctl_max_tx_window = 7; - -static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get); -static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, - int get); -static int irlap_param_max_turn_time(void *instance, irda_param_t *param, - int get); -static int irlap_param_data_size(void *instance, irda_param_t *param, int get); -static int irlap_param_window_size(void *instance, irda_param_t *param, - int get); -static int irlap_param_additional_bofs(void *instance, irda_param_t *parm, - int get); -static int irlap_param_min_turn_time(void *instance, irda_param_t *param, - int get); - -#ifndef CONFIG_IRDA_DYNAMIC_WINDOW -static __u32 irlap_requested_line_capacity(struct qos_info *qos); -#endif - -static __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */ -static __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000, - 1152000, 4000000, 16000000 }; /* bps */ -static __u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */ -static __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */ -static __u32 max_turn_times[] = { 500, 250, 100, 50 }; /* ms */ -static __u32 link_disc_times[] = { 3, 8, 12, 16, 20, 25, 30, 40 }; /* secs */ - -static __u32 max_line_capacities[10][4] = { - /* 500 ms 250 ms 100 ms 50 ms (max turn time) */ - { 100, 0, 0, 0 }, /* 2400 bps */ - { 400, 0, 0, 0 }, /* 9600 bps */ - { 800, 0, 0, 0 }, /* 19200 bps */ - { 1600, 0, 0, 0 }, /* 38400 bps */ - { 2360, 0, 0, 0 }, /* 57600 bps */ - { 4800, 2400, 960, 480 }, /* 115200 bps */ - { 28800, 11520, 5760, 2880 }, /* 576000 bps */ - { 57600, 28800, 11520, 5760 }, /* 1152000 bps */ - { 200000, 100000, 40000, 20000 }, /* 4000000 bps */ - { 800000, 400000, 160000, 80000 }, /* 16000000 bps */ -}; - -static const pi_minor_info_t pi_minor_call_table_type_0[] = { - { NULL, 0 }, -/* 01 */{ irlap_param_baud_rate, PV_INTEGER | PV_LITTLE_ENDIAN }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, -/* 08 */{ irlap_param_link_disconnect, PV_INT_8_BITS } -}; - -static const pi_minor_info_t pi_minor_call_table_type_1[] = { - { NULL, 0 }, - { NULL, 0 }, -/* 82 */{ irlap_param_max_turn_time, PV_INT_8_BITS }, -/* 83 */{ irlap_param_data_size, PV_INT_8_BITS }, -/* 84 */{ irlap_param_window_size, PV_INT_8_BITS }, -/* 85 */{ irlap_param_additional_bofs, PV_INT_8_BITS }, -/* 86 */{ irlap_param_min_turn_time, PV_INT_8_BITS }, -}; - -static const pi_major_info_t pi_major_call_table[] = { - { pi_minor_call_table_type_0, 9 }, - { pi_minor_call_table_type_1, 7 }, -}; - -static pi_param_info_t irlap_param_info = { pi_major_call_table, 2, 0x7f, 7 }; - -/* ---------------------- LOCAL SUBROUTINES ---------------------- */ -/* Note : we start with a bunch of local subroutines. - * As the compiler is "one pass", this is the only way to get them to - * inline properly... - * Jean II - */ -/* - * Function value_index (value, array, size) - * - * Returns the index to the value in the specified array - */ -static inline int value_index(__u32 value, __u32 *array, int size) -{ - int i; - - for (i=0; i < size; i++) - if (array[i] == value) - break; - return i; -} - -/* - * Function index_value (index, array) - * - * Returns value to index in array, easy! - * - */ -static inline __u32 index_value(int index, __u32 *array) -{ - return array[index]; -} - -/* - * Function msb_index (word) - * - * Returns index to most significant bit (MSB) in word - * - */ -static int msb_index (__u16 word) -{ - __u16 msb = 0x8000; - int index = 15; /* Current MSB */ - - /* Check for buggy peers. - * Note : there is a small probability that it could be us, but I - * would expect driver authors to catch that pretty early and be - * able to check precisely what's going on. If a end user sees this, - * it's very likely the peer. - Jean II */ - if (word == 0) { - net_warn_ratelimited("%s(), Detected buggy peer, adjust null PV to 0x1!\n", - __func__); - /* The only safe choice (we don't know the array size) */ - word = 0x1; - } - - while (msb) { - if (word & msb) - break; /* Found it! */ - msb >>=1; - index--; - } - return index; -} - -/* - * Function value_lower_bits (value, array) - * - * Returns a bit field marking all possibility lower than value. - */ -static inline int value_lower_bits(__u32 value, __u32 *array, int size, __u16 *field) -{ - int i; - __u16 mask = 0x1; - __u16 result = 0x0; - - for (i=0; i < size; i++) { - /* Add the current value to the bit field, shift mask */ - result |= mask; - mask <<= 1; - /* Finished ? */ - if (array[i] >= value) - break; - } - /* Send back a valid index */ - if(i >= size) - i = size - 1; /* Last item */ - *field = result; - return i; -} - -/* - * Function value_highest_bit (value, array) - * - * Returns a bit field marking the highest possibility lower than value. - */ -static inline int value_highest_bit(__u32 value, __u32 *array, int size, __u16 *field) -{ - int i; - __u16 mask = 0x1; - __u16 result = 0x0; - - for (i=0; i < size; i++) { - /* Finished ? */ - if (array[i] <= value) - break; - /* Shift mask */ - mask <<= 1; - } - /* Set the current value to the bit field */ - result |= mask; - /* Send back a valid index */ - if(i >= size) - i = size - 1; /* Last item */ - *field = result; - return i; -} - -/* -------------------------- MAIN CALLS -------------------------- */ - -/* - * Function irda_qos_compute_intersection (qos, new) - * - * Compute the intersection of the old QoS capabilities with new ones - * - */ -void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new) -{ - IRDA_ASSERT(qos != NULL, return;); - IRDA_ASSERT(new != NULL, return;); - - /* Apply */ - qos->baud_rate.bits &= new->baud_rate.bits; - qos->window_size.bits &= new->window_size.bits; - qos->min_turn_time.bits &= new->min_turn_time.bits; - qos->max_turn_time.bits &= new->max_turn_time.bits; - qos->data_size.bits &= new->data_size.bits; - qos->link_disc_time.bits &= new->link_disc_time.bits; - qos->additional_bofs.bits &= new->additional_bofs.bits; - - irda_qos_bits_to_value(qos); -} - -/* - * Function irda_init_max_qos_capabilies (qos) - * - * The purpose of this function is for layers and drivers to be able to - * set the maximum QoS possible and then "and in" their own limitations - * - */ -void irda_init_max_qos_capabilies(struct qos_info *qos) -{ - int i; - /* - * These are the maximum supported values as specified on pages - * 39-43 in IrLAP - */ - - /* Use sysctl to set some configurable values... */ - /* Set configured max speed */ - i = value_lower_bits(sysctl_max_baud_rate, baud_rates, 10, - &qos->baud_rate.bits); - sysctl_max_baud_rate = index_value(i, baud_rates); - - /* Set configured max disc time */ - i = value_lower_bits(sysctl_max_noreply_time, link_disc_times, 8, - &qos->link_disc_time.bits); - sysctl_max_noreply_time = index_value(i, link_disc_times); - - /* LSB is first byte, MSB is second byte */ - qos->baud_rate.bits &= 0x03ff; - - qos->window_size.bits = 0x7f; - qos->min_turn_time.bits = 0xff; - qos->max_turn_time.bits = 0x0f; - qos->data_size.bits = 0x3f; - qos->link_disc_time.bits &= 0xff; - qos->additional_bofs.bits = 0xff; -} -EXPORT_SYMBOL(irda_init_max_qos_capabilies); - -/* - * Function irlap_adjust_qos_settings (qos) - * - * Adjust QoS settings in case some values are not possible to use because - * of other settings - */ -static void irlap_adjust_qos_settings(struct qos_info *qos) -{ - __u32 line_capacity; - int index; - - /* - * Make sure the mintt is sensible. - * Main culprit : Ericsson T39. - Jean II - */ - if (sysctl_min_tx_turn_time > qos->min_turn_time.value) { - int i; - - net_warn_ratelimited("%s(), Detected buggy peer, adjust mtt to %dus!\n", - __func__, sysctl_min_tx_turn_time); - - /* We don't really need bits, but easier this way */ - i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times, - 8, &qos->min_turn_time.bits); - sysctl_min_tx_turn_time = index_value(i, min_turn_times); - qos->min_turn_time.value = sysctl_min_tx_turn_time; - } - - /* - * Not allowed to use a max turn time less than 500 ms if the baudrate - * is less than 115200 - */ - if ((qos->baud_rate.value < 115200) && - (qos->max_turn_time.value < 500)) - { - pr_debug("%s(), adjusting max turn time from %d to 500 ms\n", - __func__, qos->max_turn_time.value); - qos->max_turn_time.value = 500; - } - - /* - * The data size must be adjusted according to the baud rate and max - * turn time - */ - index = value_index(qos->data_size.value, data_sizes, 6); - line_capacity = irlap_max_line_capacity(qos->baud_rate.value, - qos->max_turn_time.value); - -#ifdef CONFIG_IRDA_DYNAMIC_WINDOW - while ((qos->data_size.value > line_capacity) && (index > 0)) { - qos->data_size.value = data_sizes[index--]; - pr_debug("%s(), reducing data size to %d\n", - __func__, qos->data_size.value); - } -#else /* Use method described in section 6.6.11 of IrLAP */ - while (irlap_requested_line_capacity(qos) > line_capacity) { - IRDA_ASSERT(index != 0, return;); - - /* Must be able to send at least one frame */ - if (qos->window_size.value > 1) { - qos->window_size.value--; - pr_debug("%s(), reducing window size to %d\n", - __func__, qos->window_size.value); - } else if (index > 1) { - qos->data_size.value = data_sizes[index--]; - pr_debug("%s(), reducing data size to %d\n", - __func__, qos->data_size.value); - } else { - net_warn_ratelimited("%s(), nothing more we can do!\n", - __func__); - } - } -#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ - /* - * Fix tx data size according to user limits - Jean II - */ - if (qos->data_size.value > sysctl_max_tx_data_size) - /* Allow non discrete adjustement to avoid losing capacity */ - qos->data_size.value = sysctl_max_tx_data_size; - /* - * Override Tx window if user request it. - Jean II - */ - if (qos->window_size.value > sysctl_max_tx_window) - qos->window_size.value = sysctl_max_tx_window; -} - -/* - * Function irlap_negotiate (qos_device, qos_session, skb) - * - * Negotiate QoS values, not really that much negotiation :-) - * We just set the QoS capabilities for the peer station - * - */ -int irlap_qos_negotiate(struct irlap_cb *self, struct sk_buff *skb) -{ - int ret; - - ret = irda_param_extract_all(self, skb->data, skb->len, - &irlap_param_info); - - /* Convert the negotiated bits to values */ - irda_qos_bits_to_value(&self->qos_tx); - irda_qos_bits_to_value(&self->qos_rx); - - irlap_adjust_qos_settings(&self->qos_tx); - - pr_debug("Setting BAUD_RATE to %d bps.\n", - self->qos_tx.baud_rate.value); - pr_debug("Setting DATA_SIZE to %d bytes\n", - self->qos_tx.data_size.value); - pr_debug("Setting WINDOW_SIZE to %d\n", - self->qos_tx.window_size.value); - pr_debug("Setting XBOFS to %d\n", - self->qos_tx.additional_bofs.value); - pr_debug("Setting MAX_TURN_TIME to %d ms.\n", - self->qos_tx.max_turn_time.value); - pr_debug("Setting MIN_TURN_TIME to %d usecs.\n", - self->qos_tx.min_turn_time.value); - pr_debug("Setting LINK_DISC to %d secs.\n", - self->qos_tx.link_disc_time.value); - return ret; -} - -/* - * Function irlap_insert_negotiation_params (qos, fp) - * - * Insert QoS negotiaion pararameters into frame - * - */ -int irlap_insert_qos_negotiation_params(struct irlap_cb *self, - struct sk_buff *skb) -{ - int ret; - - /* Insert data rate */ - ret = irda_param_insert(self, PI_BAUD_RATE, skb_tail_pointer(skb), - skb_tailroom(skb), &irlap_param_info); - if (ret < 0) - return ret; - skb_put(skb, ret); - - /* Insert max turnaround time */ - ret = irda_param_insert(self, PI_MAX_TURN_TIME, skb_tail_pointer(skb), - skb_tailroom(skb), &irlap_param_info); - if (ret < 0) - return ret; - skb_put(skb, ret); - - /* Insert data size */ - ret = irda_param_insert(self, PI_DATA_SIZE, skb_tail_pointer(skb), - skb_tailroom(skb), &irlap_param_info); - if (ret < 0) - return ret; - skb_put(skb, ret); - - /* Insert window size */ - ret = irda_param_insert(self, PI_WINDOW_SIZE, skb_tail_pointer(skb), - skb_tailroom(skb), &irlap_param_info); - if (ret < 0) - return ret; - skb_put(skb, ret); - - /* Insert additional BOFs */ - ret = irda_param_insert(self, PI_ADD_BOFS, skb_tail_pointer(skb), - skb_tailroom(skb), &irlap_param_info); - if (ret < 0) - return ret; - skb_put(skb, ret); - - /* Insert minimum turnaround time */ - ret = irda_param_insert(self, PI_MIN_TURN_TIME, skb_tail_pointer(skb), - skb_tailroom(skb), &irlap_param_info); - if (ret < 0) - return ret; - skb_put(skb, ret); - - /* Insert link disconnect/threshold time */ - ret = irda_param_insert(self, PI_LINK_DISC, skb_tail_pointer(skb), - skb_tailroom(skb), &irlap_param_info); - if (ret < 0) - return ret; - skb_put(skb, ret); - - return 0; -} - -/* - * Function irlap_param_baud_rate (instance, param, get) - * - * Negotiate data-rate - * - */ -static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get) -{ - __u16 final; - - struct irlap_cb *self = (struct irlap_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - if (get) { - param->pv.i = self->qos_rx.baud_rate.bits; - pr_debug("%s(), baud rate = 0x%02x\n", - __func__, param->pv.i); - } else { - /* - * Stations must agree on baud rate, so calculate - * intersection - */ - pr_debug("Requested BAUD_RATE: 0x%04x\n", (__u16)param->pv.i); - final = (__u16) param->pv.i & self->qos_rx.baud_rate.bits; - - pr_debug("Final BAUD_RATE: 0x%04x\n", final); - self->qos_tx.baud_rate.bits = final; - self->qos_rx.baud_rate.bits = final; - } - - return 0; -} - -/* - * Function irlap_param_link_disconnect (instance, param, get) - * - * Negotiate link disconnect/threshold time. - * - */ -static int irlap_param_link_disconnect(void *instance, irda_param_t *param, - int get) -{ - __u16 final; - - struct irlap_cb *self = (struct irlap_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - if (get) - param->pv.i = self->qos_rx.link_disc_time.bits; - else { - /* - * Stations must agree on link disconnect/threshold - * time. - */ - pr_debug("LINK_DISC: %02x\n", (__u8)param->pv.i); - final = (__u8) param->pv.i & self->qos_rx.link_disc_time.bits; - - pr_debug("Final LINK_DISC: %02x\n", final); - self->qos_tx.link_disc_time.bits = final; - self->qos_rx.link_disc_time.bits = final; - } - return 0; -} - -/* - * Function irlap_param_max_turn_time (instance, param, get) - * - * Negotiate the maximum turnaround time. This is a type 1 parameter and - * will be negotiated independently for each station - * - */ -static int irlap_param_max_turn_time(void *instance, irda_param_t *param, - int get) -{ - struct irlap_cb *self = (struct irlap_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - if (get) - param->pv.i = self->qos_rx.max_turn_time.bits; - else - self->qos_tx.max_turn_time.bits = (__u8) param->pv.i; - - return 0; -} - -/* - * Function irlap_param_data_size (instance, param, get) - * - * Negotiate the data size. This is a type 1 parameter and - * will be negotiated independently for each station - * - */ -static int irlap_param_data_size(void *instance, irda_param_t *param, int get) -{ - struct irlap_cb *self = (struct irlap_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - if (get) - param->pv.i = self->qos_rx.data_size.bits; - else - self->qos_tx.data_size.bits = (__u8) param->pv.i; - - return 0; -} - -/* - * Function irlap_param_window_size (instance, param, get) - * - * Negotiate the window size. This is a type 1 parameter and - * will be negotiated independently for each station - * - */ -static int irlap_param_window_size(void *instance, irda_param_t *param, - int get) -{ - struct irlap_cb *self = (struct irlap_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - if (get) - param->pv.i = self->qos_rx.window_size.bits; - else - self->qos_tx.window_size.bits = (__u8) param->pv.i; - - return 0; -} - -/* - * Function irlap_param_additional_bofs (instance, param, get) - * - * Negotiate additional BOF characters. This is a type 1 parameter and - * will be negotiated independently for each station. - */ -static int irlap_param_additional_bofs(void *instance, irda_param_t *param, int get) -{ - struct irlap_cb *self = (struct irlap_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - if (get) - param->pv.i = self->qos_rx.additional_bofs.bits; - else - self->qos_tx.additional_bofs.bits = (__u8) param->pv.i; - - return 0; -} - -/* - * Function irlap_param_min_turn_time (instance, param, get) - * - * Negotiate the minimum turn around time. This is a type 1 parameter and - * will be negotiated independently for each station - */ -static int irlap_param_min_turn_time(void *instance, irda_param_t *param, - int get) -{ - struct irlap_cb *self = (struct irlap_cb *) instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); - - if (get) - param->pv.i = self->qos_rx.min_turn_time.bits; - else - self->qos_tx.min_turn_time.bits = (__u8) param->pv.i; - - return 0; -} - -/* - * Function irlap_max_line_capacity (speed, max_turn_time, min_turn_time) - * - * Calculate the maximum line capacity - * - */ -__u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time) -{ - __u32 line_capacity; - int i,j; - - pr_debug("%s(), speed=%d, max_turn_time=%d\n", - __func__, speed, max_turn_time); - - i = value_index(speed, baud_rates, 10); - j = value_index(max_turn_time, max_turn_times, 4); - - IRDA_ASSERT(((i >=0) && (i <10)), return 0;); - IRDA_ASSERT(((j >=0) && (j <4)), return 0;); - - line_capacity = max_line_capacities[i][j]; - - pr_debug("%s(), line capacity=%d bytes\n", - __func__, line_capacity); - - return line_capacity; -} - -#ifndef CONFIG_IRDA_DYNAMIC_WINDOW -static __u32 irlap_requested_line_capacity(struct qos_info *qos) -{ - __u32 line_capacity; - - line_capacity = qos->window_size.value * - (qos->data_size.value + 6 + qos->additional_bofs.value) + - irlap_min_turn_time_in_bytes(qos->baud_rate.value, - qos->min_turn_time.value); - - pr_debug("%s(), requested line capacity=%d\n", - __func__, line_capacity); - - return line_capacity; -} -#endif - -void irda_qos_bits_to_value(struct qos_info *qos) -{ - int index; - - IRDA_ASSERT(qos != NULL, return;); - - index = msb_index(qos->baud_rate.bits); - qos->baud_rate.value = baud_rates[index]; - - index = msb_index(qos->data_size.bits); - qos->data_size.value = data_sizes[index]; - - index = msb_index(qos->window_size.bits); - qos->window_size.value = index+1; - - index = msb_index(qos->min_turn_time.bits); - qos->min_turn_time.value = min_turn_times[index]; - - index = msb_index(qos->max_turn_time.bits); - qos->max_turn_time.value = max_turn_times[index]; - - index = msb_index(qos->link_disc_time.bits); - qos->link_disc_time.value = link_disc_times[index]; - - index = msb_index(qos->additional_bofs.bits); - qos->additional_bofs.value = add_bofs[index]; -} -EXPORT_SYMBOL(irda_qos_bits_to_value); diff --git a/drivers/staging/irda/net/timer.c b/drivers/staging/irda/net/timer.c deleted file mode 100644 index cf00c0d848aa..000000000000 --- a/drivers/staging/irda/net/timer.c +++ /dev/null @@ -1,231 +0,0 @@ -/********************************************************************* - * - * Filename: timer.c - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Aug 16 00:59:29 1997 - * Modified at: Wed Dec 8 12:50:34 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/delay.h> - -#include <net/irda/timer.h> -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> -#include <net/irda/irlap.h> -#include <net/irda/irlmp.h> - -extern int sysctl_slot_timeout; - -static void irlap_slot_timer_expired(struct timer_list *t); -static void irlap_query_timer_expired(struct timer_list *t); -static void irlap_final_timer_expired(struct timer_list *t); -static void irlap_wd_timer_expired(struct timer_list *t); -static void irlap_backoff_timer_expired(struct timer_list *t); -static void irlap_media_busy_expired(struct timer_list *t); - -void irlap_start_slot_timer(struct irlap_cb *self, int timeout) -{ - irda_start_timer(&self->slot_timer, timeout, - irlap_slot_timer_expired); -} - -void irlap_start_query_timer(struct irlap_cb *self, int S, int s) -{ - int timeout; - - /* Calculate when the peer discovery should end. Normally, we - * get the end-of-discovery frame, so this is just in case - * we miss it. - * Basically, we multiply the number of remaining slots by our - * slot time, plus add some extra time to properly receive the last - * discovery packet (which is longer due to extra discovery info), - * to avoid messing with for incoming connections requests and - * to accommodate devices that perform discovery slower than us. - * Jean II */ - timeout = msecs_to_jiffies(sysctl_slot_timeout) * (S - s) - + XIDEXTRA_TIMEOUT + SMALLBUSY_TIMEOUT; - - /* Set or re-set the timer. We reset the timer for each received - * discovery query, which allow us to automatically adjust to - * the speed of the peer discovery (faster or slower). Jean II */ - irda_start_timer(&self->query_timer, timeout, - irlap_query_timer_expired); -} - -void irlap_start_final_timer(struct irlap_cb *self, int timeout) -{ - irda_start_timer(&self->final_timer, timeout, - irlap_final_timer_expired); -} - -void irlap_start_wd_timer(struct irlap_cb *self, int timeout) -{ - irda_start_timer(&self->wd_timer, timeout, - irlap_wd_timer_expired); -} - -void irlap_start_backoff_timer(struct irlap_cb *self, int timeout) -{ - irda_start_timer(&self->backoff_timer, timeout, - irlap_backoff_timer_expired); -} - -void irlap_start_mbusy_timer(struct irlap_cb *self, int timeout) -{ - irda_start_timer(&self->media_busy_timer, timeout, - irlap_media_busy_expired); -} - -void irlap_stop_mbusy_timer(struct irlap_cb *self) -{ - /* If timer is activated, kill it! */ - del_timer(&self->media_busy_timer); - - /* If we are in NDM, there is a bunch of events in LAP that - * that be pending due to the media_busy condition, such as - * CONNECT_REQUEST and SEND_UI_FRAME. If we don't generate - * an event, they will wait forever... - * Jean II */ - if (self->state == LAP_NDM) - irlap_do_event(self, MEDIA_BUSY_TIMER_EXPIRED, NULL, NULL); -} - -void irlmp_start_watchdog_timer(struct lsap_cb *self, int timeout) -{ - irda_start_timer(&self->watchdog_timer, timeout, - irlmp_watchdog_timer_expired); -} - -void irlmp_start_discovery_timer(struct irlmp_cb *self, int timeout) -{ - irda_start_timer(&self->discovery_timer, timeout, - irlmp_discovery_timer_expired); -} - -void irlmp_start_idle_timer(struct lap_cb *self, int timeout) -{ - irda_start_timer(&self->idle_timer, timeout, - irlmp_idle_timer_expired); -} - -void irlmp_stop_idle_timer(struct lap_cb *self) -{ - /* If timer is activated, kill it! */ - del_timer(&self->idle_timer); -} - -/* - * Function irlap_slot_timer_expired (data) - * - * IrLAP slot timer has expired - * - */ -static void irlap_slot_timer_expired(struct timer_list *t) -{ - struct irlap_cb *self = from_timer(self, t, slot_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_do_event(self, SLOT_TIMER_EXPIRED, NULL, NULL); -} - -/* - * Function irlap_query_timer_expired (data) - * - * IrLAP query timer has expired - * - */ -static void irlap_query_timer_expired(struct timer_list *t) -{ - struct irlap_cb *self = from_timer(self, t, query_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_do_event(self, QUERY_TIMER_EXPIRED, NULL, NULL); -} - -/* - * Function irda_final_timer_expired (data) - * - * - * - */ -static void irlap_final_timer_expired(struct timer_list *t) -{ - struct irlap_cb *self = from_timer(self, t, final_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_do_event(self, FINAL_TIMER_EXPIRED, NULL, NULL); -} - -/* - * Function irda_wd_timer_expired (data) - * - * - * - */ -static void irlap_wd_timer_expired(struct timer_list *t) -{ - struct irlap_cb *self = from_timer(self, t, wd_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_do_event(self, WD_TIMER_EXPIRED, NULL, NULL); -} - -/* - * Function irda_backoff_timer_expired (data) - * - * - * - */ -static void irlap_backoff_timer_expired(struct timer_list *t) -{ - struct irlap_cb *self = from_timer(self, t, backoff_timer); - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - - irlap_do_event(self, BACKOFF_TIMER_EXPIRED, NULL, NULL); -} - - -/* - * Function irtty_media_busy_expired (data) - * - * - */ -static void irlap_media_busy_expired(struct timer_list *t) -{ - struct irlap_cb *self = from_timer(self, t, media_busy_timer); - - IRDA_ASSERT(self != NULL, return;); - - irda_device_set_media_busy(self->netdev, FALSE); - /* Note : the LAP event will be send in irlap_stop_mbusy_timer(), - * to catch other cases where the flag is cleared (for example - * after a discovery) - Jean II */ -} diff --git a/drivers/staging/irda/net/wrapper.c b/drivers/staging/irda/net/wrapper.c deleted file mode 100644 index 40a0f993bf13..000000000000 --- a/drivers/staging/irda/net/wrapper.c +++ /dev/null @@ -1,492 +0,0 @@ -/********************************************************************* - * - * Filename: wrapper.c - * Version: 1.2 - * Description: IrDA SIR async wrapper layer - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Fri Jan 28 13:21:09 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Modified at: Fri May 28 3:11 CST 1999 - * Modified by: Horst von Brand <vonbrand@sleipnir.valparaiso.cl> - * - * Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, - * All Rights Reserved. - * Copyright (c) 2000-2002 Jean Tourrilhes <jt@hpl.hp.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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/skbuff.h> -#include <linux/string.h> -#include <linux/module.h> -#include <asm/byteorder.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include <net/irda/crc.h> -#include <net/irda/irlap.h> -#include <net/irda/irlap_frame.h> -#include <net/irda/irda_device.h> - -/************************** FRAME WRAPPING **************************/ -/* - * Unwrap and unstuff SIR frames - * - * Note : at FIR and MIR, HDLC framing is used and usually handled - * by the controller, so we come here only for SIR... Jean II - */ - -/* - * Function stuff_byte (byte, buf) - * - * Byte stuff one single byte and put the result in buffer pointed to by - * buf. The buffer must at all times be able to have two bytes inserted. - * - * This is in a tight loop, better inline it, so need to be prior to callers. - * (2000 bytes on P6 200MHz, non-inlined ~370us, inline ~170us) - Jean II - */ -static inline int stuff_byte(__u8 byte, __u8 *buf) -{ - switch (byte) { - case BOF: /* FALLTHROUGH */ - case EOF: /* FALLTHROUGH */ - case CE: - /* Insert transparently coded */ - buf[0] = CE; /* Send link escape */ - buf[1] = byte^IRDA_TRANS; /* Complement bit 5 */ - return 2; - /* break; */ - default: - /* Non-special value, no transparency required */ - buf[0] = byte; - return 1; - /* break; */ - } -} - -/* - * Function async_wrap (skb, *tx_buff, buffsize) - * - * Makes a new buffer with wrapping and stuffing, should check that - * we don't get tx buffer overflow. - */ -int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize) -{ - struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; - int xbofs; - int i; - int n; - union { - __u16 value; - __u8 bytes[2]; - } fcs; - - /* Initialize variables */ - fcs.value = INIT_FCS; - n = 0; - - /* - * Send XBOF's for required min. turn time and for the negotiated - * additional XBOFS - */ - - if (cb->magic != LAP_MAGIC) { - /* - * This will happen for all frames sent from user-space. - * Nothing to worry about, but we set the default number of - * BOF's - */ - pr_debug("%s(), wrong magic in skb!\n", __func__); - xbofs = 10; - } else - xbofs = cb->xbofs + cb->xbofs_delay; - - pr_debug("%s(), xbofs=%d\n", __func__, xbofs); - - /* Check that we never use more than 115 + 48 xbofs */ - if (xbofs > 163) { - pr_debug("%s(), too many xbofs (%d)\n", __func__, - xbofs); - xbofs = 163; - } - - memset(tx_buff + n, XBOF, xbofs); - n += xbofs; - - /* Start of packet character BOF */ - tx_buff[n++] = BOF; - - /* Insert frame and calc CRC */ - for (i=0; i < skb->len; i++) { - /* - * Check for the possibility of tx buffer overflow. We use - * bufsize-5 since the maximum number of bytes that can be - * transmitted after this point is 5. - */ - if(n >= (buffsize-5)) { - net_err_ratelimited("%s(), tx buffer overflow (n=%d)\n", - __func__, n); - return n; - } - - n += stuff_byte(skb->data[i], tx_buff+n); - fcs.value = irda_fcs(fcs.value, skb->data[i]); - } - - /* Insert CRC in little endian format (LSB first) */ - fcs.value = ~fcs.value; -#ifdef __LITTLE_ENDIAN - n += stuff_byte(fcs.bytes[0], tx_buff+n); - n += stuff_byte(fcs.bytes[1], tx_buff+n); -#else /* ifdef __BIG_ENDIAN */ - n += stuff_byte(fcs.bytes[1], tx_buff+n); - n += stuff_byte(fcs.bytes[0], tx_buff+n); -#endif - tx_buff[n++] = EOF; - - return n; -} -EXPORT_SYMBOL(async_wrap_skb); - -/************************* FRAME UNWRAPPING *************************/ -/* - * Unwrap and unstuff SIR frames - * - * Complete rewrite by Jean II : - * More inline, faster, more compact, more logical. Jean II - * (16 bytes on P6 200MHz, old 5 to 7 us, new 4 to 6 us) - * (24 bytes on P6 200MHz, old 9 to 10 us, new 7 to 8 us) - * (for reference, 115200 b/s is 1 byte every 69 us) - * And reduce wrapper.o by ~900B in the process ;-) - * - * Then, we have the addition of ZeroCopy, which is optional - * (i.e. the driver must initiate it) and improve final processing. - * (2005 B frame + EOF on P6 200MHz, without 30 to 50 us, with 10 to 25 us) - * - * Note : at FIR and MIR, HDLC framing is used and usually handled - * by the controller, so we come here only for SIR... Jean II - */ - -/* - * We can also choose where we want to do the CRC calculation. We can - * do it "inline", as we receive the bytes, or "postponed", when - * receiving the End-Of-Frame. - * (16 bytes on P6 200MHz, inlined 4 to 6 us, postponed 4 to 5 us) - * (24 bytes on P6 200MHz, inlined 7 to 8 us, postponed 5 to 7 us) - * With ZeroCopy : - * (2005 B frame on P6 200MHz, inlined 10 to 25 us, postponed 140 to 180 us) - * Without ZeroCopy : - * (2005 B frame on P6 200MHz, inlined 30 to 50 us, postponed 150 to 180 us) - * (Note : numbers taken with irq disabled) - * - * From those numbers, it's not clear which is the best strategy, because - * we end up running through a lot of data one way or another (i.e. cache - * misses). I personally prefer to avoid the huge latency spike of the - * "postponed" solution, because it come just at the time when we have - * lot's of protocol processing to do and it will hurt our ability to - * reach low link turnaround times... Jean II - */ -//#define POSTPONE_RX_CRC - -/* - * Function async_bump (buf, len, stats) - * - * Got a frame, make a copy of it, and pass it up the stack! We can try - * to inline it since it's only called from state_inside_frame - */ -static inline void -async_bump(struct net_device *dev, - struct net_device_stats *stats, - iobuff_t *rx_buff) -{ - struct sk_buff *newskb; - struct sk_buff *dataskb; - int docopy; - - /* Check if we need to copy the data to a new skb or not. - * If the driver doesn't use ZeroCopy Rx, we have to do it. - * With ZeroCopy Rx, the rx_buff already point to a valid - * skb. But, if the frame is small, it is more efficient to - * copy it to save memory (copy will be fast anyway - that's - * called Rx-copy-break). Jean II */ - docopy = ((rx_buff->skb == NULL) || - (rx_buff->len < IRDA_RX_COPY_THRESHOLD)); - - /* Allocate a new skb */ - newskb = dev_alloc_skb(docopy ? rx_buff->len + 1 : rx_buff->truesize); - if (!newskb) { - stats->rx_dropped++; - /* We could deliver the current skb if doing ZeroCopy Rx, - * but this would stall the Rx path. Better drop the - * packet... Jean II */ - return; - } - - /* Align IP header to 20 bytes (i.e. increase skb->data) - * Note this is only useful with IrLAN, as PPP has a variable - * header size (2 or 1 bytes) - Jean II */ - skb_reserve(newskb, 1); - - if(docopy) { - /* Copy data without CRC (length already checked) */ - skb_copy_to_linear_data(newskb, rx_buff->data, - rx_buff->len - 2); - /* Deliver this skb */ - dataskb = newskb; - } else { - /* We are using ZeroCopy. Deliver old skb */ - dataskb = rx_buff->skb; - /* And hook the new skb to the rx_buff */ - rx_buff->skb = newskb; - rx_buff->head = newskb->data; /* NOT newskb->head */ - //printk(KERN_DEBUG "ZeroCopy : len = %d, dataskb = %p, newskb = %p\n", rx_buff->len, dataskb, newskb); - } - - /* Set proper length on skb (without CRC) */ - skb_put(dataskb, rx_buff->len - 2); - - /* Feed it to IrLAP layer */ - dataskb->dev = dev; - skb_reset_mac_header(dataskb); - dataskb->protocol = htons(ETH_P_IRDA); - - netif_rx(dataskb); - - stats->rx_packets++; - stats->rx_bytes += rx_buff->len; - - /* Clean up rx_buff (redundant with async_unwrap_bof() ???) */ - rx_buff->data = rx_buff->head; - rx_buff->len = 0; -} - -/* - * Function async_unwrap_bof(dev, byte) - * - * Handle Beginning Of Frame character received within a frame - * - */ -static inline void -async_unwrap_bof(struct net_device *dev, - struct net_device_stats *stats, - iobuff_t *rx_buff, __u8 byte) -{ - switch(rx_buff->state) { - case LINK_ESCAPE: - case INSIDE_FRAME: - /* Not supposed to happen, the previous frame is not - * finished - Jean II */ - pr_debug("%s(), Discarding incomplete frame\n", - __func__); - stats->rx_errors++; - stats->rx_missed_errors++; - irda_device_set_media_busy(dev, TRUE); - break; - - case OUTSIDE_FRAME: - case BEGIN_FRAME: - default: - /* We may receive multiple BOF at the start of frame */ - break; - } - - /* Now receiving frame */ - rx_buff->state = BEGIN_FRAME; - rx_buff->in_frame = TRUE; - - /* Time to initialize receive buffer */ - rx_buff->data = rx_buff->head; - rx_buff->len = 0; - rx_buff->fcs = INIT_FCS; -} - -/* - * Function async_unwrap_eof(dev, byte) - * - * Handle End Of Frame character received within a frame - * - */ -static inline void -async_unwrap_eof(struct net_device *dev, - struct net_device_stats *stats, - iobuff_t *rx_buff, __u8 byte) -{ -#ifdef POSTPONE_RX_CRC - int i; -#endif - - switch(rx_buff->state) { - case OUTSIDE_FRAME: - /* Probably missed the BOF */ - stats->rx_errors++; - stats->rx_missed_errors++; - irda_device_set_media_busy(dev, TRUE); - break; - - case BEGIN_FRAME: - case LINK_ESCAPE: - case INSIDE_FRAME: - default: - /* Note : in the case of BEGIN_FRAME and LINK_ESCAPE, - * the fcs will most likely not match and generate an - * error, as expected - Jean II */ - rx_buff->state = OUTSIDE_FRAME; - rx_buff->in_frame = FALSE; - -#ifdef POSTPONE_RX_CRC - /* If we haven't done the CRC as we receive bytes, we - * must do it now... Jean II */ - for(i = 0; i < rx_buff->len; i++) - rx_buff->fcs = irda_fcs(rx_buff->fcs, - rx_buff->data[i]); -#endif - - /* Test FCS and signal success if the frame is good */ - if (rx_buff->fcs == GOOD_FCS) { - /* Deliver frame */ - async_bump(dev, stats, rx_buff); - break; - } else { - /* Wrong CRC, discard frame! */ - irda_device_set_media_busy(dev, TRUE); - - pr_debug("%s(), crc error\n", __func__); - stats->rx_errors++; - stats->rx_crc_errors++; - } - break; - } -} - -/* - * Function async_unwrap_ce(dev, byte) - * - * Handle Character Escape character received within a frame - * - */ -static inline void -async_unwrap_ce(struct net_device *dev, - struct net_device_stats *stats, - iobuff_t *rx_buff, __u8 byte) -{ - switch(rx_buff->state) { - case OUTSIDE_FRAME: - /* Activate carrier sense */ - irda_device_set_media_busy(dev, TRUE); - break; - - case LINK_ESCAPE: - net_warn_ratelimited("%s: state not defined\n", __func__); - break; - - case BEGIN_FRAME: - case INSIDE_FRAME: - default: - /* Stuffed byte coming */ - rx_buff->state = LINK_ESCAPE; - break; - } -} - -/* - * Function async_unwrap_other(dev, byte) - * - * Handle other characters received within a frame - * - */ -static inline void -async_unwrap_other(struct net_device *dev, - struct net_device_stats *stats, - iobuff_t *rx_buff, __u8 byte) -{ - switch(rx_buff->state) { - /* This is on the critical path, case are ordered by - * probability (most frequent first) - Jean II */ - case INSIDE_FRAME: - /* Must be the next byte of the frame */ - if (rx_buff->len < rx_buff->truesize) { - rx_buff->data[rx_buff->len++] = byte; -#ifndef POSTPONE_RX_CRC - rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); -#endif - } else { - pr_debug("%s(), Rx buffer overflow, aborting\n", - __func__); - rx_buff->state = OUTSIDE_FRAME; - } - break; - - case LINK_ESCAPE: - /* - * Stuffed char, complement bit 5 of byte - * following CE, IrLAP p.114 - */ - byte ^= IRDA_TRANS; - if (rx_buff->len < rx_buff->truesize) { - rx_buff->data[rx_buff->len++] = byte; -#ifndef POSTPONE_RX_CRC - rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); -#endif - rx_buff->state = INSIDE_FRAME; - } else { - pr_debug("%s(), Rx buffer overflow, aborting\n", - __func__); - rx_buff->state = OUTSIDE_FRAME; - } - break; - - case OUTSIDE_FRAME: - /* Activate carrier sense */ - if(byte != XBOF) - irda_device_set_media_busy(dev, TRUE); - break; - - case BEGIN_FRAME: - default: - rx_buff->data[rx_buff->len++] = byte; -#ifndef POSTPONE_RX_CRC - rx_buff->fcs = irda_fcs(rx_buff->fcs, byte); -#endif - rx_buff->state = INSIDE_FRAME; - break; - } -} - -/* - * Function async_unwrap_char (dev, rx_buff, byte) - * - * Parse and de-stuff frame received from the IrDA-port - * - * This is the main entry point for SIR drivers. - */ -void async_unwrap_char(struct net_device *dev, - struct net_device_stats *stats, - iobuff_t *rx_buff, __u8 byte) -{ - switch(byte) { - case CE: - async_unwrap_ce(dev, stats, rx_buff, byte); - break; - case BOF: - async_unwrap_bof(dev, stats, rx_buff, byte); - break; - case EOF: - async_unwrap_eof(dev, stats, rx_buff, byte); - break; - default: - async_unwrap_other(dev, stats, rx_buff, byte); - break; - } -} -EXPORT_SYMBOL(async_unwrap_char); - diff --git a/drivers/staging/ks7010/Makefile b/drivers/staging/ks7010/Makefile index 69fcf8d655c7..07dc16cc86f5 100644 --- a/drivers/staging/ks7010/Makefile +++ b/drivers/staging/ks7010/Makefile @@ -1,4 +1,3 @@ obj-$(CONFIG_KS7010) += ks7010.o -ccflags-y += -DKS_WLAN_DEBUG=0 ks7010-y := michael_mic.o ks_hostif.o ks_wlan_net.o ks7010_sdio.o diff --git a/drivers/staging/ks7010/eap_packet.h b/drivers/staging/ks7010/eap_packet.h index dca2a142e834..58c2a3dafca2 100644 --- a/drivers/staging/ks7010/eap_packet.h +++ b/drivers/staging/ks7010/eap_packet.h @@ -3,12 +3,8 @@ #define EAP_PACKET_H #include <linux/compiler.h> - -#define WBIT(n) (1 << (n)) - -#ifndef ETH_ALEN -#define ETH_ALEN 6 -#endif +#include <linux/bitops.h> +#include <uapi/linux/if_ether.h> #define ETHER_HDR_SIZE 20 @@ -20,9 +16,6 @@ struct ether_hdr { unsigned char h_command; unsigned char h_vendor_id[3]; __be16 h_proto; /* packet type ID field */ -#define ETHER_PROTOCOL_TYPE_EAP 0x888e -#define ETHER_PROTOCOL_TYPE_IP 0x0800 -#define ETHER_PROTOCOL_TYPE_ARP 0x0806 /* followed by length octets of data */ } __packed; @@ -104,23 +97,23 @@ struct wpa_eapol_key { /* followed by key_data_length bytes of key_data */ } __packed; -#define WPA_KEY_INFO_TYPE_MASK (WBIT(0) | WBIT(1) | WBIT(2)) -#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 WBIT(0) -#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES WBIT(1) -#define WPA_KEY_INFO_KEY_TYPE WBIT(3) /* 1 = Pairwise, 0 = Group key */ +#define WPA_KEY_INFO_TYPE_MASK GENMASK(2, 0) +#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0) +#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1) +#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */ /* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */ -#define WPA_KEY_INFO_KEY_INDEX_MASK (WBIT(4) | WBIT(5)) +#define WPA_KEY_INFO_KEY_INDEX_MASK GENMASK(5, 4) #define WPA_KEY_INFO_KEY_INDEX_SHIFT 4 -#define WPA_KEY_INFO_INSTALL WBIT(6) /* pairwise */ -#define WPA_KEY_INFO_TXRX WBIT(6) /* group */ -#define WPA_KEY_INFO_ACK WBIT(7) -#define WPA_KEY_INFO_MIC WBIT(8) -#define WPA_KEY_INFO_SECURE WBIT(9) -#define WPA_KEY_INFO_ERROR WBIT(10) -#define WPA_KEY_INFO_REQUEST WBIT(11) -#define WPA_KEY_INFO_ENCR_KEY_DATA WBIT(12) /* IEEE 802.11i/RSN only */ - -#define WPA_CAPABILITY_PREAUTH WBIT(0) +#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */ +#define WPA_KEY_INFO_TXRX BIT(6) /* group */ +#define WPA_KEY_INFO_ACK BIT(7) +#define WPA_KEY_INFO_MIC BIT(8) +#define WPA_KEY_INFO_SECURE BIT(9) +#define WPA_KEY_INFO_ERROR BIT(10) +#define WPA_KEY_INFO_REQUEST BIT(11) +#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */ + +#define WPA_CAPABILITY_PREAUTH BIT(0) #define GENERIC_INFO_ELEM 0xdd #define RSN_INFO_ELEM 0x30 diff --git a/drivers/staging/ks7010/ks7010_sdio.c b/drivers/staging/ks7010/ks7010_sdio.c index 8cfdff198334..b8f55a11ee1c 100644 --- a/drivers/staging/ks7010/ks7010_sdio.c +++ b/drivers/staging/ks7010/ks7010_sdio.c @@ -32,19 +32,39 @@ static const struct sdio_device_id ks7010_sdio_ids[] = { }; MODULE_DEVICE_TABLE(sdio, ks7010_sdio_ids); -#define inc_txqhead(priv) \ - (priv->tx_dev.qhead = (priv->tx_dev.qhead + 1) % TX_DEVICE_BUFF_SIZE) -#define inc_txqtail(priv) \ - (priv->tx_dev.qtail = (priv->tx_dev.qtail + 1) % TX_DEVICE_BUFF_SIZE) -#define cnt_txqbody(priv) \ - (((priv->tx_dev.qtail + TX_DEVICE_BUFF_SIZE) - (priv->tx_dev.qhead)) % TX_DEVICE_BUFF_SIZE) - -#define inc_rxqhead(priv) \ - (priv->rx_dev.qhead = (priv->rx_dev.qhead + 1) % RX_DEVICE_BUFF_SIZE) -#define inc_rxqtail(priv) \ - (priv->rx_dev.qtail = (priv->rx_dev.qtail + 1) % RX_DEVICE_BUFF_SIZE) -#define cnt_rxqbody(priv) \ - (((priv->rx_dev.qtail + RX_DEVICE_BUFF_SIZE) - (priv->rx_dev.qhead)) % RX_DEVICE_BUFF_SIZE) +static inline void inc_txqhead(struct ks_wlan_private *priv) +{ + priv->tx_dev.qhead = (priv->tx_dev.qhead + 1) % TX_DEVICE_BUFF_SIZE; +} + +static inline void inc_txqtail(struct ks_wlan_private *priv) +{ + priv->tx_dev.qtail = (priv->tx_dev.qtail + 1) % TX_DEVICE_BUFF_SIZE; +} + +static inline unsigned int cnt_txqbody(struct ks_wlan_private *priv) +{ + unsigned int tx_cnt = priv->tx_dev.qtail - priv->tx_dev.qhead; + + return (tx_cnt + TX_DEVICE_BUFF_SIZE) % TX_DEVICE_BUFF_SIZE; +} + +static inline void inc_rxqhead(struct ks_wlan_private *priv) +{ + priv->rx_dev.qhead = (priv->rx_dev.qhead + 1) % RX_DEVICE_BUFF_SIZE; +} + +static inline void inc_rxqtail(struct ks_wlan_private *priv) +{ + priv->rx_dev.qtail = (priv->rx_dev.qtail + 1) % RX_DEVICE_BUFF_SIZE; +} + +static inline unsigned int cnt_rxqbody(struct ks_wlan_private *priv) +{ + unsigned int rx_cnt = priv->rx_dev.qtail - priv->rx_dev.qhead; + + return (rx_cnt + RX_DEVICE_BUFF_SIZE) % RX_DEVICE_BUFF_SIZE; +} /* Read single byte from device address into byte (CMD52) */ static int ks7010_sdio_readb(struct ks_wlan_private *priv, unsigned int address, @@ -92,22 +112,17 @@ static void ks_wlan_hw_sleep_doze_request(struct ks_wlan_private *priv) { int ret; - DPRINTK(4, "\n"); - /* clear request */ atomic_set(&priv->sleepstatus.doze_request, 0); if (atomic_read(&priv->sleepstatus.status) == 0) { ret = ks7010_sdio_writeb(priv, GCR_B, GCR_B_DOZE); if (ret) { - DPRINTK(1, " error : GCR_B\n"); + netdev_err(priv->net_dev, " error : GCR_B\n"); goto set_sleep_mode; } - DPRINTK(3, "sleep_mode=SLP_SLEEP\n"); atomic_set(&priv->sleepstatus.status, 1); priv->last_doze = jiffies; - } else { - DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode); } set_sleep_mode: @@ -118,23 +133,18 @@ static void ks_wlan_hw_sleep_wakeup_request(struct ks_wlan_private *priv) { int ret; - DPRINTK(4, "\n"); - /* clear request */ atomic_set(&priv->sleepstatus.wakeup_request, 0); if (atomic_read(&priv->sleepstatus.status) == 1) { ret = ks7010_sdio_writeb(priv, WAKEUP, WAKEUP_REQ); if (ret) { - DPRINTK(1, " error : WAKEUP\n"); + netdev_err(priv->net_dev, " error : WAKEUP\n"); goto set_sleep_mode; } - DPRINTK(4, "wake up : WAKEUP\n"); atomic_set(&priv->sleepstatus.status, 0); priv->last_wakeup = jiffies; ++priv->wakeup_count; - } else { - DPRINTK(1, "sleep_mode=%d\n", priv->sleep_mode); } set_sleep_mode: @@ -145,19 +155,13 @@ void ks_wlan_hw_wakeup_request(struct ks_wlan_private *priv) { int ret; - DPRINTK(4, "\n"); if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { ret = ks7010_sdio_writeb(priv, WAKEUP, WAKEUP_REQ); if (ret) - DPRINTK(1, " error : WAKEUP\n"); - else - DPRINTK(4, "wake up : WAKEUP\n"); + netdev_err(priv->net_dev, " error : WAKEUP\n"); priv->last_wakeup = jiffies; ++priv->wakeup_count; - } else { - DPRINTK(1, "psstatus=%d\n", - atomic_read(&priv->psstatus.status)); } } @@ -181,11 +185,11 @@ static void _ks_wlan_hw_power_save(struct ks_wlan_private *priv) if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) return; - DPRINTK(5, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n", - atomic_read(&priv->psstatus.status), - atomic_read(&priv->psstatus.confirm_wait), - atomic_read(&priv->psstatus.snooze_guard), - cnt_txqbody(priv)); + netdev_dbg(priv->net_dev, "\npsstatus.status=%d\npsstatus.confirm_wait=%d\npsstatus.snooze_guard=%d\ncnt_txqbody=%d\n", + atomic_read(&priv->psstatus.status), + atomic_read(&priv->psstatus.confirm_wait), + atomic_read(&priv->psstatus.snooze_guard), + cnt_txqbody(priv)); if (atomic_read(&priv->psstatus.confirm_wait) || atomic_read(&priv->psstatus.snooze_guard) || @@ -196,7 +200,7 @@ static void _ks_wlan_hw_power_save(struct ks_wlan_private *priv) ret = ks7010_sdio_readb(priv, INT_PENDING, &byte); if (ret) { - DPRINTK(1, " error : INT_PENDING\n"); + netdev_err(priv->net_dev, " error : INT_PENDING\n"); goto queue_delayed_work; } if (byte) @@ -204,11 +208,10 @@ static void _ks_wlan_hw_power_save(struct ks_wlan_private *priv) ret = ks7010_sdio_writeb(priv, GCR_B, GCR_B_DOZE); if (ret) { - DPRINTK(1, " error : GCR_B\n"); + netdev_err(priv->net_dev, " error : GCR_B\n"); goto queue_delayed_work; } atomic_set(&priv->psstatus.status, PS_SNOOZE); - DPRINTK(3, "psstatus.status=PS_SNOOZE\n"); return; @@ -237,7 +240,7 @@ static int enqueue_txdev(struct ks_wlan_private *priv, unsigned char *p, } if ((TX_DEVICE_BUFF_SIZE - 1) <= cnt_txqbody(priv)) { - DPRINTK(1, "tx buffer overflow\n"); + netdev_err(priv->net_dev, "tx buffer overflow\n"); ret = -EOVERFLOW; goto err_complete; } @@ -268,22 +271,21 @@ static int write_to_device(struct ks_wlan_private *priv, unsigned char *buffer, hdr = (struct hostif_hdr *)buffer; - DPRINTK(4, "size=%d\n", hdr->size); if (le16_to_cpu(hdr->event) < HIF_DATA_REQ || le16_to_cpu(hdr->event) > HIF_REQ_MAX) { - DPRINTK(1, "unknown event=%04X\n", hdr->event); + netdev_err(priv->net_dev, "unknown event=%04X\n", hdr->event); return 0; } ret = ks7010_sdio_write(priv, DATA_WINDOW, buffer, size); if (ret) { - DPRINTK(1, " write error : retval=%d\n", ret); + netdev_err(priv->net_dev, " write error : retval=%d\n", ret); return ret; } ret = ks7010_sdio_writeb(priv, WRITE_STATUS, REG_STATUS_BUSY); if (ret) { - DPRINTK(1, " error : WRITE_STATUS\n"); + netdev_err(priv->net_dev, " error : WRITE_STATUS\n"); return ret; } @@ -295,7 +297,6 @@ static void tx_device_task(struct ks_wlan_private *priv) struct tx_device_buffer *sp; int ret; - DPRINTK(4, "\n"); if (cnt_txqbody(priv) <= 0 || atomic_read(&priv->psstatus.status) == PS_SNOOZE) return; @@ -304,7 +305,7 @@ static void tx_device_task(struct ks_wlan_private *priv) if (priv->dev_state >= DEVICE_STATE_BOOT) { ret = write_to_device(priv, sp->sendp, sp->size); if (ret) { - DPRINTK(1, "write_to_device error !!(%d)\n", ret); + netdev_err(priv->net_dev, "write_to_device error !!(%d)\n", ret); queue_delayed_work(priv->wq, &priv->rw_dwork, 1); return; } @@ -330,7 +331,7 @@ int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, if (le16_to_cpu(hdr->event) < HIF_DATA_REQ || le16_to_cpu(hdr->event) > HIF_REQ_MAX) { - DPRINTK(1, "unknown event=%04X\n", hdr->event); + netdev_err(priv->net_dev, "unknown event=%04X\n", hdr->event); return 0; } @@ -338,7 +339,6 @@ int ks_wlan_hw_tx(struct ks_wlan_private *priv, void *p, unsigned long size, priv->hostt.buff[priv->hostt.qtail] = le16_to_cpu(hdr->event); priv->hostt.qtail = (priv->hostt.qtail + 1) % SME_EVENT_BUFF_SIZE; - DPRINTK(4, "event=%04X\n", hdr->event); spin_lock(&priv->tx_dev.tx_dev_lock); result = enqueue_txdev(priv, p, size, complete_handler, skb); spin_unlock(&priv->tx_dev.tx_dev_lock); @@ -354,8 +354,6 @@ static void rx_event_task(unsigned long dev) struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; struct rx_device_buffer *rp; - DPRINTK(4, "\n"); - if (cnt_rxqbody(priv) > 0 && priv->dev_state >= DEVICE_STATE_BOOT) { rp = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qhead]; hostif_receive(priv, rp->data, rp->size); @@ -373,11 +371,9 @@ static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size) struct hostif_hdr *hdr; unsigned short event = 0; - DPRINTK(4, "\n"); - /* receive data */ if (cnt_rxqbody(priv) >= (RX_DEVICE_BUFF_SIZE - 1)) { - DPRINTK(1, "rx buffer overflow\n"); + netdev_err(priv->net_dev, "rx buffer overflow\n"); return; } rx_buffer = &priv->rx_dev.rx_dev_buff[priv->rx_dev.qtail]; @@ -389,15 +385,14 @@ static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size) /* length check */ if (size > 2046 || size == 0) { -#ifdef KS_WLAN_DEBUG - if (KS_WLAN_DEBUG > 5) - print_hex_dump_bytes("INVALID DATA dump: ", - DUMP_PREFIX_OFFSET, - rx_buffer->data, 32); +#ifdef DEBUG + print_hex_dump_bytes("INVALID DATA dump: ", + DUMP_PREFIX_OFFSET, + rx_buffer->data, 32); #endif ret = ks7010_sdio_writeb(priv, READ_STATUS, REG_STATUS_IDLE); if (ret) - DPRINTK(1, " error : READ_STATUS\n"); + netdev_err(priv->net_dev, " error : READ_STATUS\n"); /* length check fail */ return; @@ -410,11 +405,11 @@ static void ks_wlan_hw_rx(struct ks_wlan_private *priv, uint16_t size) ret = ks7010_sdio_writeb(priv, READ_STATUS, REG_STATUS_IDLE); if (ret) - DPRINTK(1, " error : READ_STATUS\n"); + netdev_err(priv->net_dev, " error : READ_STATUS\n"); if (atomic_read(&priv->psstatus.confirm_wait)) { if (IS_HIF_CONF(event)) { - DPRINTK(4, "IS_HIF_CONF true !!\n"); + netdev_dbg(priv->net_dev, "IS_HIF_CONF true !!\n"); atomic_dec(&priv->psstatus.confirm_wait); } } @@ -430,18 +425,16 @@ static void ks7010_rw_function(struct work_struct *work) priv = container_of(work, struct ks_wlan_private, rw_dwork.work); - DPRINTK(4, "\n"); - /* wait after DOZE */ if (time_after(priv->last_doze + ((30 * HZ) / 1000), jiffies)) { - DPRINTK(4, "wait after DOZE\n"); + netdev_dbg(priv->net_dev, "wait after DOZE\n"); queue_delayed_work(priv->wq, &priv->rw_dwork, 1); return; } /* wait after WAKEUP */ while (time_after(priv->last_wakeup + ((30 * HZ) / 1000), jiffies)) { - DPRINTK(4, "wait after WAKEUP\n"); + netdev_dbg(priv->net_dev, "wait after WAKEUP\n"); dev_info(&priv->ks_sdio_card->func->dev, "wake: %lu %lu\n", priv->last_wakeup + (30 * HZ) / 1000, @@ -474,11 +467,10 @@ static void ks7010_rw_function(struct work_struct *work) /* read (WriteStatus/ReadDataSize FN1:00_0014) */ ret = ks7010_sdio_readb(priv, WSTATUS_RSIZE, &byte); if (ret) { - DPRINTK(1, " error : WSTATUS_RSIZE psstatus=%d\n", - atomic_read(&priv->psstatus.status)); + netdev_err(priv->net_dev, " error : WSTATUS_RSIZE psstatus=%d\n", + atomic_read(&priv->psstatus.status)); goto release_host; } - DPRINTK(4, "WSTATUS_RSIZE=%02X\n", byte); if (byte & RSIZE_MASK) { /* Read schedule */ ks_wlan_hw_rx(priv, (uint16_t)((byte & RSIZE_MASK) << 4)); @@ -501,17 +493,15 @@ static void ks_sdio_interrupt(struct sdio_func *func) card = sdio_get_drvdata(func); priv = card->priv; - DPRINTK(4, "\n"); if (priv->dev_state < DEVICE_STATE_BOOT) goto queue_delayed_work; ret = ks7010_sdio_readb(priv, INT_PENDING, &status); if (ret) { - DPRINTK(1, "error : INT_PENDING\n"); + netdev_err(priv->net_dev, "error : INT_PENDING\n"); goto queue_delayed_work; } - DPRINTK(4, "INT_PENDING=%02X\n", status); /* schedule task for interrupt status */ /* bit7 -> Write General Communication B register */ @@ -522,7 +512,7 @@ static void ks_sdio_interrupt(struct sdio_func *func) atomic_read(&priv->psstatus.status) == PS_SNOOZE) { ret = ks7010_sdio_readb(priv, GCR_B, &byte); if (ret) { - DPRINTK(1, " error : GCR_B\n"); + netdev_err(priv->net_dev, " error : GCR_B\n"); goto queue_delayed_work; } if (byte == GCR_B_ACTIVE) { @@ -538,10 +528,9 @@ static void ks_sdio_interrupt(struct sdio_func *func) /* read (WriteStatus/ReadDataSize FN1:00_0014) */ ret = ks7010_sdio_readb(priv, WSTATUS_RSIZE, &byte); if (ret) { - DPRINTK(1, " error : WSTATUS_RSIZE\n"); + netdev_err(priv->net_dev, " error : WSTATUS_RSIZE\n"); goto queue_delayed_work; } - DPRINTK(4, "WSTATUS_RSIZE=%02X\n", byte); rsize = byte & RSIZE_MASK; if (rsize != 0) /* Read schedule */ ks_wlan_hw_rx(priv, (uint16_t)(rsize << 4)); @@ -638,7 +627,7 @@ static int ks7010_sdio_data_compare(struct ks_wlan_private *priv, u32 address, if (memcmp(data, read_buf, size) != 0) { ret = -EIO; - DPRINTK(0, "data compare error (%d)\n", ret); + netdev_err(priv->net_dev, "data compare error (%d)\n", ret); goto err_free_read_buf; } @@ -669,7 +658,7 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card) /* Firmware running ? */ ret = ks7010_sdio_readb(priv, GCR_A, &byte); if (byte == GCR_A_RUN) { - DPRINTK(0, "MAC firmware running ...\n"); + netdev_dbg(priv->net_dev, "MAC firmware running ...\n"); goto release_host_and_free; } @@ -689,7 +678,6 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card) size = length; length = 0; } - DPRINTK(4, "size = %d\n", size); if (size == 0) break; memcpy(rom_buf, fw_entry->data + n, size); @@ -715,8 +703,6 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card) if (ret) goto release_firmware; - DPRINTK(4, " REMAP Request : GCR_A\n"); - /* Firmware running check */ for (n = 0; n < 50; ++n) { mdelay(10); /* wait_ms(10); */ @@ -727,9 +713,8 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card) if (byte == GCR_A_RUN) break; } - DPRINTK(4, "firmware wakeup (%d)!!!!\n", n); if ((50) <= n) { - DPRINTK(1, "firmware can't start\n"); + netdev_err(priv->net_dev, "firmware can't start\n"); ret = -EIO; goto release_firmware; } @@ -747,20 +732,14 @@ static int ks7010_upload_firmware(struct ks_sdio_card *card) static void ks7010_card_init(struct ks_wlan_private *priv) { - DPRINTK(5, "\ncard_init_task()\n"); - init_completion(&priv->confirm_wait); - DPRINTK(5, "init_completion()\n"); - /* get mac address & firmware version */ hostif_sme_enqueue(priv, SME_START); - DPRINTK(5, "hostif_sme_enqueu()\n"); - if (!wait_for_completion_interruptible_timeout (&priv->confirm_wait, 5 * HZ)) { - DPRINTK(1, "wait time out!! SME_START\n"); + netdev_dbg(priv->net_dev, "wait time out!! SME_START\n"); } if (priv->mac_address_valid && priv->version_size != 0) @@ -787,14 +766,12 @@ static void ks7010_card_init(struct ks_wlan_private *priv) if (!wait_for_completion_interruptible_timeout (&priv->confirm_wait, 5 * HZ)) { - DPRINTK(1, "wait time out!! wireless parameter set\n"); + netdev_dbg(priv->net_dev, "wait time out!! wireless parameter set\n"); } if (priv->dev_state >= DEVICE_STATE_PREINIT) { - DPRINTK(1, "DEVICE READY!!\n"); + netdev_dbg(priv->net_dev, "DEVICE READY!!\n"); priv->dev_state = DEVICE_STATE_READY; - } else { - DPRINTK(1, "dev_state=%d\n", priv->dev_state); } } @@ -846,11 +823,10 @@ static int ks7010_sdio_probe(struct sdio_func *func, sdio_claim_host(func); ret = sdio_set_block_size(func, KS7010_IO_BLOCK_SIZE); - DPRINTK(5, "multi_block=%d sdio_set_block_size()=%d %d\n", + dev_dbg(&card->func->dev, "multi_block=%d sdio_set_block_size()=%d %d\n", func->card->cccr.multi_block, func->cur_blksize, ret); ret = sdio_enable_func(func); - DPRINTK(5, "sdio_enable_func() %d\n", ret); if (ret) goto err_free_card; @@ -871,7 +847,7 @@ static int ks7010_sdio_probe(struct sdio_func *func, sdio_set_drvdata(func, card); - DPRINTK(5, "class = 0x%X, vendor = 0x%X, device = 0x%X\n", + dev_dbg(&card->func->dev, "class = 0x%X, vendor = 0x%X, device = 0x%X\n", func->class, func->vendor, func->device); /* private memory allocate */ @@ -916,9 +892,9 @@ static int ks7010_sdio_probe(struct sdio_func *func, ret = ks7010_upload_firmware(card); if (ret) { - dev_err(&card->func->dev, - "ks7010: firmware load failed !! return code = %d\n", - ret); + netdev_err(priv->net_dev, + "ks7010: firmware load failed !! return code = %d\n", + ret); goto err_free_netdev; } @@ -928,7 +904,7 @@ static int ks7010_sdio_probe(struct sdio_func *func, ret = ks7010_sdio_writeb(priv, INT_PENDING, 0xff); sdio_release_host(func); if (ret) - DPRINTK(1, " error : INT_PENDING\n"); + netdev_err(priv->net_dev, " error : INT_PENDING\n"); /* enable ks7010sdio interrupt */ byte = (INT_GCR_B | INT_READ_STATUS | INT_WRITE_STATUS); @@ -936,14 +912,13 @@ static int ks7010_sdio_probe(struct sdio_func *func, ret = ks7010_sdio_writeb(priv, INT_ENABLE, byte); sdio_release_host(func); if (ret) - DPRINTK(1, " err : INT_ENABLE\n"); + netdev_err(priv->net_dev, " err : INT_ENABLE\n"); - DPRINTK(4, " enable Interrupt : INT_ENABLE=%02X\n", byte); priv->dev_state = DEVICE_STATE_BOOT; priv->wq = create_workqueue("wq"); if (!priv->wq) { - DPRINTK(1, "create_workqueue failed !!\n"); + netdev_err(priv->net_dev, "create_workqueue failed !!\n"); goto err_free_netdev; } @@ -983,7 +958,7 @@ static int send_stop_request(struct sdio_func *func) pp = kzalloc(hif_align_size(sizeof(*pp)), GFP_KERNEL); if (!pp) { - DPRINTK(3, "allocate memory failed..\n"); + netdev_err(card->priv->net_dev, "allocate memory failed..\n"); return -ENOMEM; } @@ -1011,35 +986,28 @@ static void ks7010_sdio_remove(struct sdio_func *func) if (!card) return; - DPRINTK(1, "priv = card->priv\n"); priv = card->priv; if (priv) { struct net_device *netdev = priv->net_dev; ks_wlan_net_stop(netdev); - DPRINTK(1, "ks_wlan_net_stop\n"); /* interrupt disable */ sdio_claim_host(func); sdio_writeb(func, 0, INT_ENABLE, &ret); sdio_writeb(func, 0xff, INT_PENDING, &ret); sdio_release_host(func); - DPRINTK(1, "interrupt disable\n"); ret = send_stop_request(func); if (ret) /* memory allocation failure */ return; - DPRINTK(1, "STOP Req\n"); - if (priv->wq) { flush_workqueue(priv->wq); destroy_workqueue(priv->wq); } - DPRINTK(1, "destroy_workqueue(priv->wq);\n"); hostif_exit(priv); - DPRINTK(1, "hostif_exit\n"); unregister_netdev(netdev); @@ -1050,17 +1018,10 @@ static void ks7010_sdio_remove(struct sdio_func *func) sdio_claim_host(func); sdio_release_irq(func); - DPRINTK(1, "sdio_release_irq()\n"); sdio_disable_func(func); - DPRINTK(1, "sdio_disable_func()\n"); sdio_release_host(func); - sdio_set_drvdata(func, NULL); - kfree(card); - DPRINTK(1, "kfree()\n"); - - DPRINTK(5, " Bye !!\n"); } static struct sdio_driver ks7010_sdio_driver = { diff --git a/drivers/staging/ks7010/ks_hostif.c b/drivers/staging/ks7010/ks_hostif.c index 975dbbb3abd0..676961cf4103 100644 --- a/drivers/staging/ks7010/ks_hostif.c +++ b/drivers/staging/ks7010/ks_hostif.c @@ -21,18 +21,26 @@ /* Include Wireless Extension definition and check version */ #include <net/iw_handler.h> /* New driver API */ -/* macro */ -#define inc_smeqhead(priv) \ - (priv->sme_i.qhead = (priv->sme_i.qhead + 1) % SME_EVENT_BUFF_SIZE) -#define inc_smeqtail(priv) \ - (priv->sme_i.qtail = (priv->sme_i.qtail + 1) % SME_EVENT_BUFF_SIZE) -#define cnt_smeqbody(priv) \ - (((priv->sme_i.qtail + SME_EVENT_BUFF_SIZE) - (priv->sme_i.qhead)) % SME_EVENT_BUFF_SIZE) +static inline void inc_smeqhead(struct ks_wlan_private *priv) +{ + priv->sme_i.qhead = (priv->sme_i.qhead + 1) % SME_EVENT_BUFF_SIZE; +} + +static inline void inc_smeqtail(struct ks_wlan_private *priv) +{ + priv->sme_i.qtail = (priv->sme_i.qtail + 1) % SME_EVENT_BUFF_SIZE; +} + +static inline unsigned int cnt_smeqbody(struct ks_wlan_private *priv) +{ + unsigned int sme_cnt = priv->sme_i.qtail - priv->sme_i.qhead; + + return (sme_cnt + SME_EVENT_BUFF_SIZE) % SME_EVENT_BUFF_SIZE; +} #define KS_WLAN_MEM_FLAG (GFP_ATOMIC) -static -inline u8 get_BYTE(struct ks_wlan_private *priv) +static inline u8 get_byte(struct ks_wlan_private *priv) { u8 data; @@ -42,25 +50,23 @@ inline u8 get_BYTE(struct ks_wlan_private *priv) return data; } -static -inline u16 get_WORD(struct ks_wlan_private *priv) +static inline u16 get_word(struct ks_wlan_private *priv) { u16 data; - data = (get_BYTE(priv) & 0xff); - data |= ((get_BYTE(priv) << 8) & 0xff00); + data = (get_byte(priv) & 0xff); + data |= ((get_byte(priv) << 8) & 0xff00); return data; } -static -inline u32 get_DWORD(struct ks_wlan_private *priv) +static inline u32 get_dword(struct ks_wlan_private *priv) { u32 data; - data = (get_BYTE(priv) & 0xff); - data |= ((get_BYTE(priv) << 8) & 0x0000ff00); - data |= ((get_BYTE(priv) << 16) & 0x00ff0000); - data |= ((get_BYTE(priv) << 24) & 0xff000000); + data = (get_byte(priv) & 0xff); + data |= ((get_byte(priv) << 8) & 0x0000ff00); + data |= ((get_byte(priv) << 16) & 0x00ff0000); + data |= ((get_byte(priv) << 24) & 0xff000000); return data; } @@ -79,26 +85,20 @@ static void ks_wlan_hw_wakeup_task(struct work_struct *work) &priv->psstatus.wakeup_wait, msecs_to_jiffies(20)); if (time_left <= 0) { - DPRINTK(1, "wake up timeout or interrupted !!!\n"); + netdev_dbg(priv->net_dev, "wake up timeout or interrupted !!!\n"); schedule_work(&priv->wakeup_work); return; } - } else { - DPRINTK(1, "ps_status=%d\n", ps_status); } /* power save */ - if (atomic_read(&priv->sme_task.count) > 0) { - DPRINTK(4, "sme task enable.\n"); + if (atomic_read(&priv->sme_task.count) > 0) tasklet_enable(&priv->sme_task); - } } static int ks_wlan_do_power_save(struct ks_wlan_private *priv) { - DPRINTK(4, "psstatus.status=%d\n", atomic_read(&priv->psstatus.status)); - if (is_connect_status(priv->connect_status)) hostif_sme_enqueue(priv, SME_POW_MNGMT_REQUEST); else @@ -113,7 +113,6 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info) union iwreq_data wrqu; struct net_device *netdev = priv->net_dev; - DPRINTK(3, "\n"); ap = &priv->current_ap; if (is_disconnect_status(priv->connect_status)) { @@ -186,34 +185,43 @@ int get_current_ap(struct ks_wlan_private *priv, struct link_ap_info_t *ap_info) if (is_connect_status(priv->connect_status)) { memcpy(wrqu.ap_addr.sa_data, priv->current_ap.bssid, ETH_ALEN); - DPRINTK(3, - "IWEVENT: connect bssid=%pM\n", wrqu.ap_addr.sa_data); + netdev_dbg(priv->net_dev, + "IWEVENT: connect bssid=%pM\n", wrqu.ap_addr.sa_data); wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL); } - DPRINTK(4, "\n Link AP\n"); - DPRINTK(4, " bssid=%02X:%02X:%02X:%02X:%02X:%02X\n" + netdev_dbg(priv->net_dev, " Link AP\n"); + netdev_dbg(priv->net_dev, " bssid=%02X:%02X:%02X:%02X:%02X:%02X\n" " essid=%s\n" " rate_set=%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X\n" " channel=%d\n" " rssi=%d\n" " sq=%d\n" " capability=%04X\n", - ap->bssid[0], ap->bssid[1], ap->bssid[2], - ap->bssid[3], ap->bssid[4], ap->bssid[5], - &(ap->ssid.body[0]), - ap->rate_set.body[0], ap->rate_set.body[1], - ap->rate_set.body[2], ap->rate_set.body[3], - ap->rate_set.body[4], ap->rate_set.body[5], - ap->rate_set.body[6], ap->rate_set.body[7], - ap->channel, ap->rssi, ap->sq, ap->capability); - DPRINTK(4, "\n Link AP\n rsn.mode=%d\n rsn.size=%d\n", - ap_info->rsn_mode, ap_info->rsn.size); - DPRINTK(4, "\n ext_rate_set_size=%d\n rate_set_size=%d\n", - ap_info->ext_rate_set.size, ap_info->rate_set.size); + ap->bssid[0], ap->bssid[1], ap->bssid[2], + ap->bssid[3], ap->bssid[4], ap->bssid[5], + &(ap->ssid.body[0]), + ap->rate_set.body[0], ap->rate_set.body[1], + ap->rate_set.body[2], ap->rate_set.body[3], + ap->rate_set.body[4], ap->rate_set.body[5], + ap->rate_set.body[6], ap->rate_set.body[7], + ap->channel, ap->rssi, ap->sq, ap->capability); + netdev_dbg(priv->net_dev, " Link AP\n rsn.mode=%d\n rsn.size=%d\n", + ap_info->rsn_mode, ap_info->rsn.size); + netdev_dbg(priv->net_dev, " ext_rate_set_size=%d\n rate_set_size=%d\n", + ap_info->ext_rate_set.size, ap_info->rate_set.size); return 0; } +static u8 read_ie(unsigned char *bp, u8 max, u8 *body) +{ + u8 size = (*(bp + 1) <= max) ? *(bp + 1) : max; + + memcpy(body, bp + 2, size); + return size; +} + + static int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, struct local_ap_t *ap) @@ -221,7 +229,6 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, unsigned char *bp; int bsize, offset; - DPRINTK(3, "\n"); memset(ap, 0, sizeof(struct local_ap_t)); /* bssid */ @@ -242,28 +249,19 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, offset = 0; while (bsize > offset) { - /* DPRINTK(4, "Element ID=%d\n",*bp); */ - switch (*bp) { - case 0: /* ssid */ - if (*(bp + 1) <= SSID_MAX_SIZE) { - ap->ssid.size = *(bp + 1); - } else { - DPRINTK(1, "size over :: ssid size=%d\n", - *(bp + 1)); - ap->ssid.size = SSID_MAX_SIZE; - } - memcpy(ap->ssid.body, bp + 2, ap->ssid.size); + switch (*bp) { /* Information Element ID */ + case WLAN_EID_SSID: + ap->ssid.size = read_ie(bp, IEEE80211_MAX_SSID_LEN, + ap->ssid.body); break; - case 1: /* rate */ - case 50: /* ext rate */ + case WLAN_EID_SUPP_RATES: + case WLAN_EID_EXT_SUPP_RATES: if ((*(bp + 1) + ap->rate_set.size) <= RATE_SET_MAX_SIZE) { memcpy(&ap->rate_set.body[ap->rate_set.size], bp + 2, *(bp + 1)); ap->rate_set.size += *(bp + 1); } else { - DPRINTK(1, "size over :: rate size=%d\n", - (*(bp + 1) + ap->rate_set.size)); memcpy(&ap->rate_set.body[ap->rate_set.size], bp + 2, RATE_SET_MAX_SIZE - ap->rate_set.size); @@ -271,47 +269,34 @@ int get_ap_information(struct ks_wlan_private *priv, struct ap_info_t *ap_info, (RATE_SET_MAX_SIZE - ap->rate_set.size); } break; - case 3: /* DS parameter */ + case WLAN_EID_DS_PARAMS: break; - case 48: /* RSN(WPA2) */ + case WLAN_EID_RSN: ap->rsn_ie.id = *bp; - if (*(bp + 1) <= RSN_IE_BODY_MAX) { - ap->rsn_ie.size = *(bp + 1); - } else { - DPRINTK(1, "size over :: rsn size=%d\n", - *(bp + 1)); - ap->rsn_ie.size = RSN_IE_BODY_MAX; - } - memcpy(ap->rsn_ie.body, bp + 2, ap->rsn_ie.size); + ap->rsn_ie.size = read_ie(bp, RSN_IE_BODY_MAX, + ap->rsn_ie.body); break; - case 221: /* WPA */ - if (memcmp(bp + 2, "\x00\x50\xf2\x01", 4) == 0) { /* WPA OUI check */ + case WLAN_EID_VENDOR_SPECIFIC: /* WPA */ + /* WPA OUI check */ + if (memcmp(bp + 2, CIPHER_ID_WPA_WEP40, 4) == 0) { ap->wpa_ie.id = *bp; - if (*(bp + 1) <= RSN_IE_BODY_MAX) { - ap->wpa_ie.size = *(bp + 1); - } else { - DPRINTK(1, - "size over :: wpa size=%d\n", - *(bp + 1)); - ap->wpa_ie.size = RSN_IE_BODY_MAX; - } - memcpy(ap->wpa_ie.body, bp + 2, - ap->wpa_ie.size); + ap->wpa_ie.size = read_ie(bp, RSN_IE_BODY_MAX, + ap->wpa_ie.body); } break; - case 2: /* FH parameter */ - case 4: /* CF parameter */ - case 5: /* TIM */ - case 6: /* IBSS parameter */ - case 7: /* Country */ - case 42: /* ERP information */ - case 47: /* Reserve ID 47 Broadcom AP */ + case WLAN_EID_FH_PARAMS: + case WLAN_EID_CF_PARAMS: + case WLAN_EID_TIM: + case WLAN_EID_IBSS_PARAMS: + case WLAN_EID_COUNTRY: + case WLAN_EID_ERP_INFO: break; default: - DPRINTK(4, "unknown Element ID=%d\n", *bp); + netdev_err(priv->net_dev, "unknown Element ID=%d\n", *bp); break; } + offset += 2; /* id & size field */ offset += *(bp + 1); /* +size offset */ bp += (*(bp + 1) + 2); /* pointer update */ @@ -339,7 +324,7 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv, eth_proto = ntohs(eth_hdr->h_proto); if (eth_hdr->h_dest_snap != eth_hdr->h_source_snap) { - DPRINTK(1, "invalid data format\n"); + netdev_err(priv->net_dev, "invalid data format\n"); priv->nstats.rx_errors++; return -EINVAL; } @@ -350,20 +335,20 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv, (auth_type == TYPE_GMK2 && priv->wpa.group_suite == IW_AUTH_CIPHER_TKIP)) && key->key_len) { - DPRINTK(4, "TKIP: protocol=%04X: size=%u\n", - eth_proto, priv->rx_size); + netdev_dbg(priv->net_dev, "TKIP: protocol=%04X: size=%u\n", + eth_proto, priv->rx_size); /* MIC save */ memcpy(&recv_mic[0], (priv->rxp) + ((priv->rx_size) - 8), 8); priv->rx_size = priv->rx_size - 8; if (auth_type > 0 && auth_type < 4) { /* auth_type check */ - MichaelMICFunction(&michael_mic, - (uint8_t *)key->rx_mic_key, - (uint8_t *)priv->rxp, - (int)priv->rx_size, - (uint8_t)0, /* priority */ - (uint8_t *)michael_mic.Result); + michael_mic_function(&michael_mic, + (uint8_t *)key->rx_mic_key, + (uint8_t *)priv->rxp, + (int)priv->rx_size, + (uint8_t)0, /* priority */ + (uint8_t *)michael_mic.result); } - if (memcmp(michael_mic.Result, recv_mic, 8) != 0) { + if (memcmp(michael_mic.result, recv_mic, 8) != 0) { now = jiffies; mic_failure = &priv->wpa.mic_failure; /* MIC FAILURE */ @@ -371,7 +356,7 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv, (now - mic_failure->last_failure_time) / HZ >= 60) { mic_failure->failure = 0; } - DPRINTK(4, "MIC FAILURE\n"); + netdev_err(priv->net_dev, "MIC FAILURE\n"); if (mic_failure->failure == 0) { mic_failure->failure = 1; mic_failure->counter = 0; @@ -392,7 +377,6 @@ int hostif_data_indication_wpa(struct ks_wlan_private *priv, eth_hdr->h_source); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); - DPRINTK(4, "IWEVENT:MICHAELMICFAILURE\n"); wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); return -EINVAL; @@ -414,30 +398,26 @@ void hostif_data_indication(struct ks_wlan_private *priv) size_t size; int ret; - DPRINTK(3, "\n"); - /* min length check */ if (priv->rx_size <= ETH_HLEN) { - DPRINTK(3, "rx_size = %d\n", priv->rx_size); priv->nstats.rx_errors++; return; } - auth_type = get_WORD(priv); /* AuthType */ - get_WORD(priv); /* Reserve Area */ + auth_type = get_word(priv); /* AuthType */ + get_word(priv); /* Reserve Area */ eth_hdr = (struct ether_hdr *)(priv->rxp); eth_proto = ntohs(eth_hdr->h_proto); - DPRINTK(3, "ether protocol = %04X\n", eth_proto); /* source address check */ if (memcmp(&priv->eth_addr[0], eth_hdr->h_source, ETH_ALEN) == 0) { - DPRINTK(1, "invalid : source is own mac address !!\n"); - DPRINTK(1, - "eth_hdrernet->h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", - eth_hdr->h_source[0], eth_hdr->h_source[1], - eth_hdr->h_source[2], eth_hdr->h_source[3], - eth_hdr->h_source[4], eth_hdr->h_source[5]); + netdev_err(priv->net_dev, "invalid : source is own mac address !!\n"); + netdev_err(priv->net_dev, + "eth_hdrernet->h_dest=%02X:%02X:%02X:%02X:%02X:%02X\n", + eth_hdr->h_source[0], eth_hdr->h_source[1], + eth_hdr->h_source[2], eth_hdr->h_source[3], + eth_hdr->h_source[4], eth_hdr->h_source[5]); priv->nstats.rx_errors++; return; } @@ -463,7 +443,8 @@ void hostif_data_indication(struct ks_wlan_private *priv) priv->nstats.rx_dropped++; return; } - DPRINTK(4, "SNAP, rx_ind_size = %d\n", rx_ind_size); + netdev_dbg(priv->net_dev, "SNAP, rx_ind_size = %d\n", + rx_ind_size); size = ETH_ALEN * 2; skb_put_data(skb, priv->rxp, size); @@ -482,20 +463,24 @@ void hostif_data_indication(struct ks_wlan_private *priv) priv->nstats.rx_dropped++; return; } - DPRINTK(3, "NETBEUI/NetBIOS rx_ind_size=%d\n", rx_ind_size); + netdev_dbg(priv->net_dev, "NETBEUI/NetBIOS rx_ind_size=%d\n", + rx_ind_size); - skb_put_data(skb, priv->rxp, 12); /* 8802/FDDI MAC copy */ + /* 8802/FDDI MAC copy */ + skb_put_data(skb, priv->rxp, 12); - temp[0] = (((rx_ind_size - 12) >> 8) & 0xff); /* NETBEUI size add */ + /* NETBEUI size add */ + temp[0] = (((rx_ind_size - 12) >> 8) & 0xff); temp[1] = ((rx_ind_size - 12) & 0xff); skb_put_data(skb, temp, 2); - skb_put_data(skb, priv->rxp + 12, rx_ind_size - 14); /* copy after Type */ + /* copy after Type */ + skb_put_data(skb, priv->rxp + 12, rx_ind_size - 14); aa1x_hdr = (struct ieee802_1x_hdr *)(priv->rxp + 14); break; default: /* other rx data */ - DPRINTK(2, "invalid data format\n"); + netdev_err(priv->net_dev, "invalid data format\n"); priv->nstats.rx_errors++; return; } @@ -521,27 +506,24 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv) u16 mib_val_size; u16 mib_val_type; - DPRINTK(3, "\n"); - - mib_status = get_DWORD(priv); /* MIB status */ - mib_attribute = get_DWORD(priv); /* MIB atttibute */ - mib_val_size = get_WORD(priv); /* MIB value size */ - mib_val_type = get_WORD(priv); /* MIB value type */ + mib_status = get_dword(priv); /* MIB status */ + mib_attribute = get_dword(priv); /* MIB atttibute */ + mib_val_size = get_word(priv); /* MIB value size */ + mib_val_type = get_word(priv); /* MIB value type */ if (mib_status) { /* in case of error */ - DPRINTK(1, "attribute=%08X, status=%08X\n", mib_attribute, - mib_status); + netdev_err(priv->net_dev, "attribute=%08X, status=%08X\n", + mib_attribute, mib_status); return; } switch (mib_attribute) { case DOT11_MAC_ADDRESS: /* MAC address */ - DPRINTK(3, " mib_attribute=DOT11_MAC_ADDRESS\n"); hostif_sme_enqueue(priv, SME_GET_MAC_ADDRESS); memcpy(priv->eth_addr, priv->rxp, ETH_ALEN); - priv->mac_address_valid = 1; + priv->mac_address_valid = true; dev->dev_addr[0] = priv->eth_addr[0]; dev->dev_addr[1] = priv->eth_addr[1]; dev->dev_addr[2] = priv->eth_addr[2]; @@ -554,7 +536,6 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv) break; case DOT11_PRODUCT_VERSION: /* firmware version */ - DPRINTK(3, " mib_attribute=DOT11_PRODUCT_VERSION\n"); priv->version_size = priv->rx_size; memcpy(priv->firmware_version, priv->rxp, priv->rx_size); priv->firmware_version[priv->rx_size] = '\0'; @@ -566,14 +547,12 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv) break; case LOCAL_GAIN: memcpy(&priv->gain, priv->rxp, sizeof(priv->gain)); - DPRINTK(3, "tx_mode=%d, rx_mode=%d, tx_gain=%d, rx_gain=%d\n", - priv->gain.tx_mode, priv->gain.rx_mode, - priv->gain.tx_gain, priv->gain.rx_gain); + netdev_dbg(priv->net_dev, "tx_mode=%d, rx_mode=%d, tx_gain=%d, rx_gain=%d\n", + priv->gain.tx_mode, priv->gain.rx_mode, + priv->gain.tx_gain, priv->gain.rx_gain); break; case LOCAL_EEPROM_SUM: memcpy(&priv->eeprom_sum, priv->rxp, sizeof(priv->eeprom_sum)); - DPRINTK(1, "eeprom_sum.type=%x, eeprom_sum.result=%x\n", - priv->eeprom_sum.type, priv->eeprom_sum.result); if (priv->eeprom_sum.type == 0) { priv->eeprom_checksum = EEPROM_CHECKSUM_NONE; } else if (priv->eeprom_sum.type == 1) { @@ -588,7 +567,8 @@ void hostif_mib_get_confirm(struct ks_wlan_private *priv) } break; default: - DPRINTK(1, "mib_attribute=%08x\n", (unsigned int)mib_attribute); + netdev_err(priv->net_dev, "mib_attribute=%08x\n", + (unsigned int)mib_attribute); break; } } @@ -599,15 +579,13 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) u32 mib_status; /* +04 MIB Status */ u32 mib_attribute; /* +08 MIB attribute */ - DPRINTK(3, "\n"); - - mib_status = get_DWORD(priv); /* MIB Status */ - mib_attribute = get_DWORD(priv); /* MIB attribute */ + mib_status = get_dword(priv); /* MIB Status */ + mib_attribute = get_dword(priv); /* MIB attribute */ if (mib_status) { /* in case of error */ - DPRINTK(1, "error :: attribute=%08X, status=%08X\n", - mib_attribute, mib_status); + netdev_err(priv->net_dev, "error :: attribute=%08X, status=%08X\n", + mib_attribute, mib_status); } switch (mib_attribute) { @@ -622,32 +600,24 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) hostif_sme_enqueue(priv, SME_WEP_INDEX_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE1: - DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE1:mib_status=%d\n", - (int)mib_status); if (priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_SET_PMK_TSC); else hostif_sme_enqueue(priv, SME_WEP_KEY1_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE2: - DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE2:mib_status=%d\n", - (int)mib_status); if (priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_SET_GMK1_TSC); else hostif_sme_enqueue(priv, SME_WEP_KEY2_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE3: - DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE3:mib_status=%d\n", - (int)mib_status); if (priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_SET_GMK2_TSC); else hostif_sme_enqueue(priv, SME_WEP_KEY3_CONFIRM); break; case DOT11_WEP_DEFAULT_KEY_VALUE4: - DPRINTK(2, "DOT11_WEP_DEFAULT_KEY_VALUE4:mib_status=%d\n", - (int)mib_status); if (!priv->wpa.rsn_enabled) hostif_sme_enqueue(priv, SME_WEP_KEY4_CONFIRM); break; @@ -656,8 +626,6 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) hostif_sme_enqueue(priv, SME_WEP_FLAG_CONFIRM); break; case DOT11_RSN_ENABLED: - DPRINTK(2, "DOT11_RSN_ENABLED:mib_status=%d\n", - (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_ENABLED_CONFIRM); break; case LOCAL_RSN_MODE: @@ -670,53 +638,38 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) hostif_sme_enqueue(priv, SME_MULTICAST_CONFIRM); break; case LOCAL_CURRENTADDRESS: - priv->mac_address_valid = 1; + priv->mac_address_valid = true; break; case DOT11_RSN_CONFIG_MULTICAST_CIPHER: - DPRINTK(2, "DOT11_RSN_CONFIG_MULTICAST_CIPHER:mib_status=%d\n", - (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_MCAST_CONFIRM); break; case DOT11_RSN_CONFIG_UNICAST_CIPHER: - DPRINTK(2, "DOT11_RSN_CONFIG_UNICAST_CIPHER:mib_status=%d\n", - (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_UCAST_CONFIRM); break; case DOT11_RSN_CONFIG_AUTH_SUITE: - DPRINTK(2, "DOT11_RSN_CONFIG_AUTH_SUITE:mib_status=%d\n", - (int)mib_status); hostif_sme_enqueue(priv, SME_RSN_AUTH_CONFIRM); break; case DOT11_PMK_TSC: - DPRINTK(2, "DOT11_PMK_TSC:mib_status=%d\n", (int)mib_status); break; case DOT11_GMK1_TSC: - DPRINTK(2, "DOT11_GMK1_TSC:mib_status=%d\n", (int)mib_status); if (atomic_read(&priv->psstatus.snooze_guard)) atomic_set(&priv->psstatus.snooze_guard, 0); break; case DOT11_GMK2_TSC: - DPRINTK(2, "DOT11_GMK2_TSC:mib_status=%d\n", (int)mib_status); if (atomic_read(&priv->psstatus.snooze_guard)) atomic_set(&priv->psstatus.snooze_guard, 0); break; case LOCAL_PMK: - DPRINTK(2, "LOCAL_PMK:mib_status=%d\n", (int)mib_status); break; case LOCAL_GAIN: - DPRINTK(2, "LOCAL_GAIN:mib_status=%d\n", (int)mib_status); break; #ifdef WPS case LOCAL_WPS_ENABLE: - DPRINTK(2, "LOCAL_WPS_ENABLE:mib_status=%d\n", (int)mib_status); break; case LOCAL_WPS_PROBE_REQ: - DPRINTK(2, "LOCAL_WPS_PROBE_REQ:mib_status=%d\n", - (int)mib_status); break; #endif /* WPS */ case LOCAL_REGION: - DPRINTK(2, "LOCAL_REGION:mib_status=%d\n", (int)mib_status); default: break; } @@ -725,8 +678,6 @@ void hostif_mib_set_confirm(struct ks_wlan_private *priv) static void hostif_power_mgmt_confirm(struct ks_wlan_private *priv) { - DPRINTK(3, "\n"); - if (priv->reg.power_mgmt > POWER_MGMT_ACTIVE && priv->reg.operation_mode == MODE_INFRASTRUCTURE) { atomic_set(&priv->psstatus.confirm_wait, 0); @@ -740,8 +691,6 @@ void hostif_power_mgmt_confirm(struct ks_wlan_private *priv) static void hostif_sleep_confirm(struct ks_wlan_private *priv) { - DPRINTK(3, "\n"); - atomic_set(&priv->sleepstatus.doze_request, 1); queue_delayed_work(priv->wq, &priv->rw_dwork, 1); } @@ -757,11 +706,10 @@ void hostif_start_confirm(struct ks_wlan_private *priv) wrqu.ap_addr.sa_family = ARPHRD_ETHER; if (is_connect_status(priv->connect_status)) { eth_zero_addr(wrqu.ap_addr.sa_data); - DPRINTK(3, "IWEVENT: disconnect\n"); wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); } #endif - DPRINTK(3, " scan_ind_count=%d\n", priv->scan_ind_count); + netdev_dbg(priv->net_dev, " scan_ind_count=%d\n", priv->scan_ind_count); hostif_sme_enqueue(priv, SME_START_CONFIRM); } @@ -774,27 +722,23 @@ void hostif_connect_indication(struct ks_wlan_private *priv) struct net_device *netdev = priv->net_dev; union iwreq_data wrqu0; - connect_code = get_WORD(priv); + connect_code = get_word(priv); switch (connect_code) { case RESULT_CONNECT: /* connect */ - DPRINTK(3, "connect :: scan_ind_count=%d\n", - priv->scan_ind_count); if (!(priv->connect_status & FORCE_DISCONNECT)) netif_carrier_on(netdev); tmp = FORCE_DISCONNECT & priv->connect_status; priv->connect_status = tmp + CONNECT_STATUS; break; - case RESULT_DISCONNECT: /* disconnect */ - DPRINTK(3, "disconnect :: scan_ind_count=%d\n", - priv->scan_ind_count); + case RESULT_DISCONNECT: /* disconnect */ netif_carrier_off(netdev); tmp = FORCE_DISCONNECT & priv->connect_status; priv->connect_status = tmp + DISCONNECT_STATUS; break; default: - DPRINTK(1, "unknown connect_code=%d :: scan_ind_count=%d\n", - connect_code, priv->scan_ind_count); + netdev_dbg(priv->net_dev, "unknown connect_code=%d :: scan_ind_count=%d\n", + connect_code, priv->scan_ind_count); netif_carrier_off(netdev); tmp = FORCE_DISCONNECT & priv->connect_status; priv->connect_status = tmp + DISCONNECT_STATUS; @@ -816,9 +760,8 @@ void hostif_connect_indication(struct ks_wlan_private *priv) if (is_disconnect_status(priv->connect_status) && is_connect_status(old_status)) { eth_zero_addr(wrqu0.ap_addr.sa_data); - DPRINTK(3, "IWEVENT: disconnect\n"); - DPRINTK(3, "disconnect :: scan_ind_count=%d\n", - priv->scan_ind_count); + netdev_dbg(priv->net_dev, "disconnect :: scan_ind_count=%d\n", + priv->scan_ind_count); wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL); } priv->scan_ind_count = 0; @@ -830,16 +773,18 @@ void hostif_scan_indication(struct ks_wlan_private *priv) int i; struct ap_info_t *ap_info; - DPRINTK(3, "scan_ind_count = %d\n", priv->scan_ind_count); + netdev_dbg(priv->net_dev, "scan_ind_count = %d\n", priv->scan_ind_count); ap_info = (struct ap_info_t *)(priv->rxp); if (priv->scan_ind_count) { - for (i = 0; i < priv->aplist.size; i++) { /* bssid check */ - if (memcmp(ap_info->bssid, - priv->aplist.ap[i].bssid, ETH_ALEN) != 0) + /* bssid check */ + for (i = 0; i < priv->aplist.size; i++) { + u8 *bssid = priv->aplist.ap[i].bssid; + + if (ether_addr_equal(ap_info->bssid, bssid)) continue; - if (ap_info->frame_type == FRAME_TYPE_PROBE_RESP) + if (ap_info->frame_type == IEEE80211_STYPE_PROBE_RESP) get_ap_information(priv, ap_info, &priv->aplist.ap[i]); return; @@ -847,14 +792,14 @@ void hostif_scan_indication(struct ks_wlan_private *priv) } priv->scan_ind_count++; if (priv->scan_ind_count < LOCAL_APLIST_MAX + 1) { - DPRINTK(4, " scan_ind_count=%d :: aplist.size=%d\n", + netdev_dbg(priv->net_dev, " scan_ind_count=%d :: aplist.size=%d\n", priv->scan_ind_count, priv->aplist.size); get_ap_information(priv, (struct ap_info_t *)(priv->rxp), &(priv->aplist.ap[priv->scan_ind_count - 1])); priv->aplist.size = priv->scan_ind_count; } else { - DPRINTK(4, " count over :: scan_ind_count=%d\n", - priv->scan_ind_count); + netdev_dbg(priv->net_dev, " count over :: scan_ind_count=%d\n", + priv->scan_ind_count); } } @@ -866,7 +811,6 @@ void hostif_stop_confirm(struct ks_wlan_private *priv) struct net_device *netdev = priv->net_dev; union iwreq_data wrqu0; - DPRINTK(3, "\n"); if (priv->dev_state == DEVICE_STATE_SLEEP) priv->dev_state = DEVICE_STATE_READY; @@ -883,10 +827,7 @@ void hostif_stop_confirm(struct ks_wlan_private *priv) if (is_disconnect_status(priv->connect_status) && is_connect_status(old_status)) { eth_zero_addr(wrqu0.ap_addr.sa_data); - DPRINTK(3, "IWEVENT: disconnect\n"); netdev_info(netdev, "IWEVENT: disconnect\n"); - DPRINTK(3, "disconnect :: scan_ind_count=%d\n", - priv->scan_ind_count); wireless_send_event(netdev, SIOCGIWAP, &wrqu0, NULL); } priv->scan_ind_count = 0; @@ -898,7 +839,6 @@ void hostif_stop_confirm(struct ks_wlan_private *priv) static void hostif_ps_adhoc_set_confirm(struct ks_wlan_private *priv) { - DPRINTK(3, "\n"); priv->infra_status = 0; /* infrastructure mode cancel */ hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); } @@ -908,9 +848,7 @@ void hostif_infrastructure_set_confirm(struct ks_wlan_private *priv) { u16 result_code; - DPRINTK(3, "\n"); - result_code = get_WORD(priv); - DPRINTK(3, "result code = %d\n", result_code); + result_code = get_word(priv); priv->infra_status = 1; /* infrastructure mode set */ hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); } @@ -918,7 +856,6 @@ void hostif_infrastructure_set_confirm(struct ks_wlan_private *priv) static void hostif_adhoc_set_confirm(struct ks_wlan_private *priv) { - DPRINTK(3, "\n"); priv->infra_status = 1; /* infrastructure mode set */ hostif_sme_enqueue(priv, SME_MODE_SET_CONFIRM); } @@ -937,7 +874,6 @@ void hostif_associate_indication(struct ks_wlan_private *priv) static const char associnfo_leader0[] = "ASSOCINFO(ReqIEs="; static const char associnfo_leader1[] = " RespIEs="; - DPRINTK(3, "\n"); assoc_req = (struct association_request_t *)(priv->rxp); assoc_resp = (struct association_response_t *)(assoc_req + 1); pb = (unsigned char *)(assoc_resp + 1); @@ -963,7 +899,6 @@ void hostif_associate_indication(struct ks_wlan_private *priv) pbuf += sprintf(pbuf, ")"); wrqu.data.length += 1; - DPRINTK(3, "IWEVENT:ASSOCINFO\n"); wireless_send_event(priv->net_dev, IWEVCUSTOM, &wrqu, buf); } @@ -974,16 +909,15 @@ void hostif_bss_scan_confirm(struct ks_wlan_private *priv) struct net_device *dev = priv->net_dev; union iwreq_data wrqu; - result_code = get_DWORD(priv); - DPRINTK(2, "result=%d :: scan_ind_count=%d\n", result_code, - priv->scan_ind_count); + result_code = get_dword(priv); + netdev_dbg(priv->net_dev, "result=%d :: scan_ind_count=%d\n", result_code, + priv->scan_ind_count); priv->sme_i.sme_flag &= ~SME_AP_SCAN; hostif_sme_enqueue(priv, SME_BSS_SCAN_CONFIRM); wrqu.data.length = 0; wrqu.data.flags = 0; - DPRINTK(3, "IWEVENT: SCAN CONFIRM\n"); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); priv->scan_ind_count = 0; } @@ -997,32 +931,32 @@ void hostif_phy_information_confirm(struct ks_wlan_private *priv) unsigned int transmitted_frame_count, received_fragment_count; unsigned int failed_count, fcs_error_count; - DPRINTK(3, "\n"); - rssi = get_BYTE(priv); - signal = get_BYTE(priv); - noise = get_BYTE(priv); - link_speed = get_BYTE(priv); - transmitted_frame_count = get_DWORD(priv); - received_fragment_count = get_DWORD(priv); - failed_count = get_DWORD(priv); - fcs_error_count = get_DWORD(priv); - - DPRINTK(4, "phyinfo confirm rssi=%d signal=%d\n", rssi, signal); + rssi = get_byte(priv); + signal = get_byte(priv); + noise = get_byte(priv); + link_speed = get_byte(priv); + transmitted_frame_count = get_dword(priv); + received_fragment_count = get_dword(priv); + failed_count = get_dword(priv); + fcs_error_count = get_dword(priv); + + netdev_dbg(priv->net_dev, "phyinfo confirm rssi=%d signal=%d\n", + rssi, signal); priv->current_rate = (link_speed & RATE_MASK); wstats->qual.qual = signal; wstats->qual.level = 256 - rssi; wstats->qual.noise = 0; /* invalid noise value */ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - DPRINTK(3, "\n rssi=%u\n" + netdev_dbg(priv->net_dev, "\n rssi=%u\n" " signal=%u\n" " link_speed=%ux500Kbps\n" " transmitted_frame_count=%u\n" " received_fragment_count=%u\n" " failed_count=%u\n" " fcs_error_count=%u\n", - rssi, signal, link_speed, transmitted_frame_count, - received_fragment_count, failed_count, fcs_error_count); + rssi, signal, link_speed, transmitted_frame_count, + received_fragment_count, failed_count, fcs_error_count); /* wake_up_interruptible_all(&priv->confirm_wait); */ complete(&priv->confirm_wait); } @@ -1030,7 +964,7 @@ void hostif_phy_information_confirm(struct ks_wlan_private *priv) static void hostif_mic_failure_confirm(struct ks_wlan_private *priv) { - DPRINTK(3, "mic_failure=%u\n", priv->wpa.mic_failure.failure); + netdev_dbg(priv->net_dev, "mic_failure=%u\n", priv->wpa.mic_failure.failure); hostif_sme_enqueue(priv, SME_MIC_FAILURE_CONFIRM); } @@ -1039,8 +973,7 @@ void hostif_event_check(struct ks_wlan_private *priv) { unsigned short event; - DPRINTK(4, "\n"); - event = get_WORD(priv); /* get event */ + event = get_word(priv); /* get event */ switch (event) { case HIF_DATA_IND: hostif_data_indication(priv); @@ -1095,7 +1028,6 @@ void hostif_event_check(struct ks_wlan_private *priv) break; case HIF_AP_SET_CONF: default: - //DPRINTK(1, "undefined event[%04X]\n", event); netdev_err(priv->net_dev, "undefined event[%04X]\n", event); /* wake_up_all(&priv->confirm_wait); */ complete(&priv->confirm_wait); @@ -1143,7 +1075,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) skb_len = skb->len; if (skb_len > ETH_FRAME_LEN) { - DPRINTK(1, "bad length skb_len=%d\n", skb_len); + netdev_err(priv->net_dev, "bad length skb_len=%d\n", skb_len); ret = -EOVERFLOW; goto err_kfree_skb; } @@ -1151,7 +1083,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) if (is_disconnect_status(priv->connect_status) || (priv->connect_status & FORCE_DISCONNECT) || priv->wpa.mic_failure.stop) { - DPRINTK(3, " DISCONNECT\n"); if (netif_queue_stopped(priv->net_dev)) netif_wake_queue(priv->net_dev); if (skb) @@ -1160,8 +1091,8 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) return 0; } - /* for PowerSave */ - if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { /* power save wakeup */ + /* power save wakeup */ + if (atomic_read(&priv->psstatus.status) == PS_SNOOZE) { if (!netif_queue_stopped(priv->net_dev)) netif_stop_queue(priv->net_dev); } @@ -1181,8 +1112,8 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) /* skb check */ eth = (struct ethhdr *)skb->data; if (memcmp(&priv->eth_addr[0], eth->h_source, ETH_ALEN) != 0) { - DPRINTK(1, "invalid mac address !!\n"); - DPRINTK(1, "ethernet->h_source=%pM\n", eth->h_source); + netdev_err(priv->net_dev, "invalid mac address !!\n"); + netdev_err(priv->net_dev, "ethernet->h_source=%pM\n", eth->h_source); ret = -ENXIO; goto err_kfree; } @@ -1197,7 +1128,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) /* EtherType/Length check */ if (*(buffer + 1) + (*buffer << 8) > 1500) { /* ProtocolEAP = *(buffer+1) + (*buffer << 8); */ - /* DPRINTK(2, "Send [SNAP]Type %x\n",ProtocolEAP); */ + /* netdev_dbg(priv->net_dev, "Send [SNAP]Type %x\n",ProtocolEAP); */ /* SAP/CTL/OUI(6 byte) add */ *p++ = 0xAA; /* DSAP */ *p++ = 0xAA; /* SSAP */ @@ -1207,7 +1138,6 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) *p++ = 0x00; /* OUI ("000000") */ skb_len += 6; } else { - DPRINTK(4, "DIX\n"); /* Length(2 byte) delete */ buffer += 2; length -= 2; @@ -1224,7 +1154,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) eth_proto = ntohs(eth_hdr->h_proto); /* for MIC FAILURE REPORT check */ - if (eth_proto == ETHER_PROTOCOL_TYPE_EAP && + if (eth_proto == ETH_P_PAE && priv->wpa.mic_failure.failure > 0) { aa1x_hdr = (struct ieee802_1x_hdr *)(eth_hdr + 1); if (aa1x_hdr->type == IEEE802_1X_TYPE_EAPOL_KEY) { @@ -1234,20 +1164,21 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) } if (priv->wpa.rsn_enabled && priv->wpa.key[0].key_len) { - if (eth_proto == ETHER_PROTOCOL_TYPE_EAP && + /* no encryption */ + if (eth_proto == ETH_P_PAE && priv->wpa.key[1].key_len == 0 && priv->wpa.key[2].key_len == 0 && priv->wpa.key[3].key_len == 0) { - pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); /* no encryption */ + pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); } else { if (priv->wpa.pairwise_suite == IW_AUTH_CIPHER_TKIP) { - MichaelMICFunction(&michael_mic, - (uint8_t *)priv->wpa.key[0].tx_mic_key, - (uint8_t *)&pp->data[0], - (int)skb_len, - (uint8_t)0, /* priority */ - (uint8_t *)michael_mic.Result); - memcpy(p, michael_mic.Result, 8); + michael_mic_function(&michael_mic, + (uint8_t *)priv->wpa.key[0].tx_mic_key, + (uint8_t *)&pp->data[0], + (int)skb_len, + (uint8_t)0, /* priority */ + (uint8_t *)michael_mic.result); + memcpy(p, michael_mic.result, 8); length += 8; skb_len += 8; p += 8; @@ -1261,7 +1192,7 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) } } } else { - if (eth_proto == ETHER_PROTOCOL_TYPE_EAP) + if (eth_proto == ETH_P_PAE) pp->auth_type = cpu_to_le16((uint16_t)TYPE_AUTH); else pp->auth_type = cpu_to_le16((uint16_t)TYPE_DATA); @@ -1278,11 +1209,11 @@ int hostif_data_request(struct ks_wlan_private *priv, struct sk_buff *skb) send_packet_complete, skb); /* MIC FAILURE REPORT check */ - if (eth_proto == ETHER_PROTOCOL_TYPE_EAP && + if (eth_proto == ETH_P_PAE && priv->wpa.mic_failure.failure > 0) { if (keyinfo & WPA_KEY_INFO_ERROR && keyinfo & WPA_KEY_INFO_REQUEST) { - DPRINTK(3, " MIC ERROR Report SET : %04X\n", keyinfo); + netdev_err(priv->net_dev, " MIC ERROR Report SET : %04X\n", keyinfo); hostif_sme_enqueue(priv, SME_MIC_FAILURE_REQUEST); } if (priv->wpa.mic_failure.failure == 2) @@ -1299,11 +1230,11 @@ err_kfree_skb: return ret; } -#define ps_confirm_wait_inc(priv) \ - do { \ - if (atomic_read(&priv->psstatus.status) > PS_ACTIVE_SET) \ - atomic_inc(&priv->psstatus.confirm_wait); \ - } while (0) +static inline void ps_confirm_wait_inc(struct ks_wlan_private *priv) +{ + if (atomic_read(&priv->psstatus.status) > PS_ACTIVE_SET) + atomic_inc(&priv->psstatus.confirm_wait); +} static void hostif_mib_get_request(struct ks_wlan_private *priv, @@ -1311,8 +1242,6 @@ void hostif_mib_get_request(struct ks_wlan_private *priv, { struct hostif_mib_get_request_t *pp; - DPRINTK(3, "\n"); - pp = hostif_generic_request(sizeof(*pp), HIF_MIB_GET_REQ); if (!pp) return; @@ -1331,12 +1260,8 @@ void hostif_mib_set_request(struct ks_wlan_private *priv, { struct hostif_mib_set_request_t *pp; - DPRINTK(3, "\n"); - - if (priv->dev_state < DEVICE_STATE_BOOT) { - DPRINTK(3, "DeviceRemove\n"); + if (priv->dev_state < DEVICE_STATE_BOOT) return; - } pp = hostif_generic_request(sizeof(*pp), HIF_MIB_SET_REQ); if (!pp) @@ -1357,8 +1282,6 @@ void hostif_start_request(struct ks_wlan_private *priv, unsigned char mode) { struct hostif_start_request_t *pp; - DPRINTK(3, "\n"); - pp = hostif_generic_request(sizeof(*pp), HIF_START_REQ); if (!pp) return; @@ -1373,137 +1296,63 @@ void hostif_start_request(struct ks_wlan_private *priv, unsigned char mode) priv->scan_ind_count = 0; } -static -void hostif_ps_adhoc_set_request(struct ks_wlan_private *priv) +static __le16 ks_wlan_cap(struct ks_wlan_private *priv) { - struct hostif_ps_adhoc_set_request_t *pp; - u16 capability; + u16 capability = 0x0000; - DPRINTK(3, "\n"); + if (priv->reg.preamble == SHORT_PREAMBLE) + capability |= WLAN_CAPABILITY_SHORT_PREAMBLE; - pp = hostif_generic_request(sizeof(*pp), HIF_PS_ADH_SET_REQ); - if (!pp) - return; + capability &= ~(WLAN_CAPABILITY_PBCC); /* pbcc not support */ - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); - pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel)); - pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], - priv->reg.rate_set.size); - - capability = 0x0000; - if (priv->reg.preamble == SHORT_PREAMBLE) { - /* short preamble */ - capability |= BSS_CAP_SHORT_PREAMBLE; - } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ if (priv->reg.phy_type != D_11B_ONLY_MODE) { - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM */ + capability |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + capability &= ~(WLAN_CAPABILITY_DSSS_OFDM); } - pp->capability = cpu_to_le16((uint16_t)capability); - /* send to device request */ - ps_confirm_wait_inc(priv); - ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL); + return cpu_to_le16((uint16_t)capability); } -static -void hostif_infrastructure_set_request(struct ks_wlan_private *priv) +static void init_request(struct ks_wlan_private *priv, struct hostif_request_t *req) { - struct hostif_infrastructure_set_request_t *pp; - u16 capability; + req->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); + req->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); + req->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + req->rate_set.size = priv->reg.rate_set.size; + req->capability = ks_wlan_cap(priv); + memcpy(&req->rate_set.body[0], &priv->reg.rate_set.body[0], + priv->reg.rate_set.size); +} - DPRINTK(3, "ssid.size=%d\n", priv->reg.ssid.size); +static +void hostif_ps_adhoc_set_request(struct ks_wlan_private *priv) +{ + struct hostif_ps_adhoc_set_request_t *pp; - pp = hostif_generic_request(sizeof(*pp), HIF_INFRA_SET_REQ); + pp = hostif_generic_request(sizeof(*pp), HIF_PS_ADH_SET_REQ); if (!pp) return; - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); - - pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], - priv->reg.rate_set.size); - pp->ssid.size = priv->reg.ssid.size; - memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); - - capability = 0x0000; - if (priv->reg.preamble == SHORT_PREAMBLE) { - /* short preamble */ - capability |= BSS_CAP_SHORT_PREAMBLE; - } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if (priv->reg.phy_type != D_11B_ONLY_MODE) { - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ - } - pp->capability = cpu_to_le16((uint16_t)capability); - pp->beacon_lost_count = - cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count)); - pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type)); - - pp->channel_list.body[0] = 1; - pp->channel_list.body[1] = 8; - pp->channel_list.body[2] = 2; - pp->channel_list.body[3] = 9; - pp->channel_list.body[4] = 3; - pp->channel_list.body[5] = 10; - pp->channel_list.body[6] = 4; - pp->channel_list.body[7] = 11; - pp->channel_list.body[8] = 5; - pp->channel_list.body[9] = 12; - pp->channel_list.body[10] = 6; - pp->channel_list.body[11] = 13; - pp->channel_list.body[12] = 7; - if (priv->reg.phy_type == D_11G_ONLY_MODE) { - pp->channel_list.size = 13; - } else { - pp->channel_list.body[13] = 14; - pp->channel_list.size = 14; - } + init_request(priv, &pp->request); + pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel)); /* send to device request */ ps_confirm_wait_inc(priv); ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL); } -static void hostif_infrastructure_set2_request(struct ks_wlan_private *priv) +static +void hostif_infrastructure_set_request(struct ks_wlan_private *priv, int event) { - struct hostif_infrastructure_set2_request_t *pp; - u16 capability; - - DPRINTK(2, "ssid.size=%d\n", priv->reg.ssid.size); + struct hostif_infrastructure_set_request_t *pp; - pp = hostif_generic_request(sizeof(*pp), HIF_INFRA_SET2_REQ); + pp = hostif_generic_request(sizeof(*pp), event); if (!pp) return; - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); - - pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], - priv->reg.rate_set.size); + init_request(priv, &pp->request); pp->ssid.size = priv->reg.ssid.size; memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); - - capability = 0x0000; - if (priv->reg.preamble == SHORT_PREAMBLE) { - /* short preamble */ - capability |= BSS_CAP_SHORT_PREAMBLE; - } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if (priv->reg.phy_type != D_11B_ONLY_MODE) { - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ - } - pp->capability = cpu_to_le16((uint16_t)capability); pp->beacon_lost_count = cpu_to_le16((uint16_t)(priv->reg.beacon_lost_count)); pp->auth_type = cpu_to_le16((uint16_t)(priv->reg.authenticate_type)); @@ -1528,8 +1377,6 @@ static void hostif_infrastructure_set2_request(struct ks_wlan_private *priv) pp->channel_list.size = 14; } - memcpy(pp->bssid, priv->reg.bssid, ETH_ALEN); - /* send to device request */ ps_confirm_wait_inc(priv); ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL); @@ -1539,36 +1386,16 @@ static void hostif_adhoc_set_request(struct ks_wlan_private *priv) { struct hostif_adhoc_set_request_t *pp; - u16 capability; - - DPRINTK(3, "\n"); pp = hostif_generic_request(sizeof(*pp), HIF_ADH_SET_REQ); if (!pp) return; - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); + init_request(priv, &pp->request); pp->channel = cpu_to_le16((uint16_t)(priv->reg.channel)); - pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], - priv->reg.rate_set.size); pp->ssid.size = priv->reg.ssid.size; memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); - capability = 0x0000; - if (priv->reg.preamble == SHORT_PREAMBLE) { - /* short preamble */ - capability |= BSS_CAP_SHORT_PREAMBLE; - } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if (priv->reg.phy_type != D_11B_ONLY_MODE) { - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ - } - pp->capability = cpu_to_le16((uint16_t)capability); - /* send to device request */ ps_confirm_wait_inc(priv); ks_wlan_hw_tx(priv, pp, hif_align_size(sizeof(*pp)), NULL, NULL); @@ -1578,35 +1405,15 @@ static void hostif_adhoc_set2_request(struct ks_wlan_private *priv) { struct hostif_adhoc_set2_request_t *pp; - u16 capability; - - DPRINTK(3, "\n"); pp = hostif_generic_request(sizeof(*pp), HIF_ADH_SET_REQ); if (!pp) return; - pp->phy_type = cpu_to_le16((uint16_t)(priv->reg.phy_type)); - pp->cts_mode = cpu_to_le16((uint16_t)(priv->reg.cts_mode)); - pp->scan_type = cpu_to_le16((uint16_t)(priv->reg.scan_type)); - pp->rate_set.size = priv->reg.rate_set.size; - memcpy(&pp->rate_set.body[0], &priv->reg.rate_set.body[0], - priv->reg.rate_set.size); + init_request(priv, &pp->request); pp->ssid.size = priv->reg.ssid.size; memcpy(&pp->ssid.body[0], &priv->reg.ssid.body[0], priv->reg.ssid.size); - capability = 0x0000; - if (priv->reg.preamble == SHORT_PREAMBLE) { - /* short preamble */ - capability |= BSS_CAP_SHORT_PREAMBLE; - } - capability &= ~(BSS_CAP_PBCC); /* pbcc not support */ - if (priv->reg.phy_type != D_11B_ONLY_MODE) { - capability |= BSS_CAP_SHORT_SLOT_TIME; /* ShortSlotTime support */ - capability &= ~(BSS_CAP_DSSS_OFDM); /* DSSS OFDM not support */ - } - pp->capability = cpu_to_le16((uint16_t)capability); - pp->channel_list.body[0] = priv->reg.channel; pp->channel_list.size = 1; memcpy(pp->bssid, priv->reg.bssid, ETH_ALEN); @@ -1621,8 +1428,6 @@ void hostif_stop_request(struct ks_wlan_private *priv) { struct hostif_stop_request_t *pp; - DPRINTK(3, "\n"); - pp = hostif_generic_request(sizeof(*pp), HIF_STOP_REQ); if (!pp) return; @@ -1637,8 +1442,6 @@ void hostif_phy_information_request(struct ks_wlan_private *priv) { struct hostif_phy_information_request_t *pp; - DPRINTK(3, "\n"); - pp = hostif_generic_request(sizeof(*pp), HIF_PHY_INFO_REQ); if (!pp) return; @@ -1663,9 +1466,6 @@ void hostif_power_mgmt_request(struct ks_wlan_private *priv, { struct hostif_power_mgmt_request_t *pp; - DPRINTK(3, "mode=%lu wake_up=%lu receive_dtims=%lu\n", mode, wake_up, - receive_dtims); - pp = hostif_generic_request(sizeof(*pp), HIF_POWER_MGMT_REQ); if (!pp) return; @@ -1685,8 +1485,6 @@ void hostif_sleep_request(struct ks_wlan_private *priv, { struct hostif_sleep_request_t *pp; - DPRINTK(3, "mode=%lu\n", (long)mode); - if (mode == SLP_SLEEP) { pp = hostif_generic_request(sizeof(*pp), HIF_SLEEP_REQ); if (!pp) @@ -1700,7 +1498,7 @@ void hostif_sleep_request(struct ks_wlan_private *priv, atomic_set(&priv->sleepstatus.wakeup_request, 1); queue_delayed_work(priv->wq, &priv->rw_dwork, 1); } else { - DPRINTK(3, "invalid mode %ld\n", (long)mode); + netdev_err(priv->net_dev, "invalid mode %ld\n", (long)mode); return; } } @@ -1712,8 +1510,6 @@ void hostif_bss_scan_request(struct ks_wlan_private *priv, { struct hostif_bss_scan_request_t *pp; - DPRINTK(2, "\n"); - pp = hostif_generic_request(sizeof(*pp), HIF_SCAN_REQ); if (!pp) return; @@ -1764,8 +1560,6 @@ void hostif_mic_failure_request(struct ks_wlan_private *priv, { struct hostif_mic_failure_request_t *pp; - DPRINTK(3, "count=%d :: timer=%d\n", failure_count, timer); - pp = hostif_generic_request(sizeof(*pp), HIF_MIC_FAILURE_REQ); if (!pp) return; @@ -1805,14 +1599,12 @@ static void devio_rec_ind(struct ks_wlan_private *priv, unsigned char *p, void hostif_receive(struct ks_wlan_private *priv, unsigned char *p, unsigned int size) { - DPRINTK(4, "\n"); - devio_rec_ind(priv, p, size); priv->rxp = p; priv->rx_size = size; - if (get_WORD(priv) == priv->rx_size) { /* length check !! */ + if (get_word(priv) == priv->rx_size) { /* length check !! */ hostif_event_check(priv); /* event check */ } } @@ -2137,11 +1929,11 @@ void hostif_sme_mode_setup(struct ks_wlan_private *priv) case MODE_INFRASTRUCTURE: /* Infrastructure mode */ if (!is_valid_ether_addr((u8 *)priv->reg.bssid)) { - hostif_infrastructure_set_request(priv); + hostif_infrastructure_set_request(priv, HIF_INFRA_SET_REQ); } else { - hostif_infrastructure_set2_request(priv); - DPRINTK(2, - "Infra bssid = %pM\n", priv->reg.bssid); + hostif_infrastructure_set_request(priv, HIF_INFRA_SET2_REQ); + netdev_dbg(priv->net_dev, + "Infra bssid = %pM\n", priv->reg.bssid); } break; case MODE_ADHOC: @@ -2150,8 +1942,8 @@ void hostif_sme_mode_setup(struct ks_wlan_private *priv) hostif_adhoc_set_request(priv); } else { hostif_adhoc_set2_request(priv); - DPRINTK(2, - "Adhoc bssid = %pM\n", priv->reg.bssid); + netdev_dbg(priv->net_dev, + "Adhoc bssid = %pM\n", priv->reg.bssid); } break; default: @@ -2169,8 +1961,6 @@ void hostif_sme_multicast_set(struct ks_wlan_private *priv) __le32 filter_type; int i = 0; - DPRINTK(3, "\n"); - spin_lock(&priv->multicast_spin); memset(set_address, 0, NIC_MAX_MCAST_LIST * ETH_ALEN); @@ -2220,7 +2010,6 @@ void hostif_sme_power_mgmt_set(struct ks_wlan_private *priv) { unsigned long mode, wake_up, receive_dtims; - DPRINTK(3, "\n"); switch (priv->reg.power_mgmt) { case POWER_MGMT_ACTIVE: mode = POWER_ACTIVE; @@ -2261,7 +2050,6 @@ void hostif_sme_power_mgmt_set(struct ks_wlan_private *priv) static void hostif_sme_sleep_set(struct ks_wlan_private *priv) { - DPRINTK(3, "\n"); switch (priv->sleep_mode) { case SLP_SLEEP: hostif_sleep_request(priv, priv->sleep_mode); @@ -2345,7 +2133,6 @@ void hostif_sme_set_pmksa(struct ks_wlan_private *priv) struct pmk_t *pmk; int i; - DPRINTK(4, "pmklist.size=%d\n", priv->pmklist.size); i = 0; list_for_each_entry(pmk, &priv->pmklist.head, list) { if (i < PMK_LIST_MAX) { @@ -2369,7 +2156,6 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) { __le32 val; - DPRINTK(3, "event=%d\n", event); switch (event) { case SME_START: if (priv->dev_state == DEVICE_STATE_BOOT) @@ -2403,8 +2189,8 @@ void hostif_sme_execute(struct ks_wlan_private *priv, int event) priv->wpa.mic_failure.failure - 1, priv->wpa.mic_failure.counter); } else { - DPRINTK(4, "SME_MIC_FAILURE_REQUEST: failure count=%u error?\n", - priv->wpa.mic_failure.failure); + netdev_err(priv->net_dev, "SME_MIC_FAILURE_REQUEST: failure count=%u error?\n", + priv->wpa.mic_failure.failure); } break; case SME_MIC_FAILURE_CONFIRM: @@ -2544,8 +2330,6 @@ void hostif_sme_task(unsigned long dev) { struct ks_wlan_private *priv = (struct ks_wlan_private *)dev; - DPRINTK(3, "\n"); - if (priv->dev_state < DEVICE_STATE_BOOT) return; @@ -2561,16 +2345,10 @@ void hostif_sme_task(unsigned long dev) /* send to Station Management Entity module */ void hostif_sme_enqueue(struct ks_wlan_private *priv, unsigned short event) { - DPRINTK(3, "\n"); - /* enqueue sme event */ if (cnt_smeqbody(priv) < (SME_EVENT_BUFF_SIZE - 1)) { priv->sme_i.event_buff[priv->sme_i.qtail] = event; inc_smeqtail(priv); -#ifdef KS_WLAN_DEBUG - if (priv->sme_i.max_event_count < cnt_smeqbody(priv)) - priv->sme_i.max_event_count = cnt_smeqbody(priv); -#endif /* KS_WLAN_DEBUG */ } else { /* in case of buffer overflow */ netdev_err(priv->net_dev, "sme queue buffer overflow\n"); @@ -2579,55 +2357,79 @@ void hostif_sme_enqueue(struct ks_wlan_private *priv, unsigned short event) tasklet_schedule(&priv->sme_task); } -int hostif_init(struct ks_wlan_private *priv) +static inline void hostif_aplist_init(struct ks_wlan_private *priv) { - int i; - - DPRINTK(3, "\n"); - + size_t size = LOCAL_APLIST_MAX * sizeof(struct local_ap_t); priv->aplist.size = 0; - for (i = 0; i < LOCAL_APLIST_MAX; i++) - memset(&priv->aplist.ap[i], 0, sizeof(struct local_ap_t)); + memset(&priv->aplist.ap[0], 0, size); +} + +static inline void hostif_status_init(struct ks_wlan_private *priv) +{ priv->infra_status = 0; priv->current_rate = 4; priv->connect_status = DISCONNECT_STATUS; +} - spin_lock_init(&priv->multicast_spin); +static inline void hostif_sme_init(struct ks_wlan_private *priv) +{ + priv->sme_i.sme_status = SME_IDLE; + priv->sme_i.qhead = 0; + priv->sme_i.qtail = 0; + spin_lock_init(&priv->sme_i.sme_spin); + priv->sme_i.sme_flag = 0; + tasklet_init(&priv->sme_task, hostif_sme_task, (unsigned long)priv); +} - spin_lock_init(&priv->dev_read_lock); - init_waitqueue_head(&priv->devread_wait); - priv->dev_count = 0; - atomic_set(&priv->event_count, 0); - atomic_set(&priv->rec_count, 0); +static inline void hostif_wpa_init(struct ks_wlan_private *priv) +{ + memset(&priv->wpa, 0, sizeof(priv->wpa)); + priv->wpa.rsn_enabled = 0; + priv->wpa.mic_failure.failure = 0; + priv->wpa.mic_failure.last_failure_time = 0; + priv->wpa.mic_failure.stop = 0; +} - /* for power save */ +static inline void hostif_power_save_init(struct ks_wlan_private *priv) +{ atomic_set(&priv->psstatus.status, PS_NONE); atomic_set(&priv->psstatus.confirm_wait, 0); atomic_set(&priv->psstatus.snooze_guard, 0); init_completion(&priv->psstatus.wakeup_wait); INIT_WORK(&priv->wakeup_work, ks_wlan_hw_wakeup_task); +} + +static inline void hostif_pmklist_init(struct ks_wlan_private *priv) +{ + int i; - /* WPA */ - memset(&priv->wpa, 0, sizeof(priv->wpa)); - priv->wpa.rsn_enabled = 0; - priv->wpa.mic_failure.failure = 0; - priv->wpa.mic_failure.last_failure_time = 0; - priv->wpa.mic_failure.stop = 0; memset(&priv->pmklist, 0, sizeof(priv->pmklist)); INIT_LIST_HEAD(&priv->pmklist.head); for (i = 0; i < PMK_LIST_MAX; i++) INIT_LIST_HEAD(&priv->pmklist.pmk[i].list); +} - priv->sme_i.sme_status = SME_IDLE; - priv->sme_i.qhead = 0; - priv->sme_i.qtail = 0; -#ifdef KS_WLAN_DEBUG - priv->sme_i.max_event_count = 0; -#endif - spin_lock_init(&priv->sme_i.sme_spin); - priv->sme_i.sme_flag = 0; +static inline void hostif_counters_init(struct ks_wlan_private *priv) +{ + priv->dev_count = 0; + atomic_set(&priv->event_count, 0); + atomic_set(&priv->rec_count, 0); +} - tasklet_init(&priv->sme_task, hostif_sme_task, (unsigned long)priv); +int hostif_init(struct ks_wlan_private *priv) +{ + hostif_aplist_init(priv); + hostif_status_init(priv); + + spin_lock_init(&priv->multicast_spin); + spin_lock_init(&priv->dev_read_lock); + init_waitqueue_head(&priv->devread_wait); + + hostif_counters_init(priv); + hostif_power_save_init(priv); + hostif_wpa_init(priv); + hostif_pmklist_init(priv); + hostif_sme_init(priv); return 0; } diff --git a/drivers/staging/ks7010/ks_hostif.h b/drivers/staging/ks7010/ks_hostif.h index 5bae8d468e23..2f918b11b337 100644 --- a/drivers/staging/ks7010/ks_hostif.h +++ b/drivers/staging/ks7010/ks_hostif.h @@ -13,6 +13,7 @@ #define _KS_HOSTIF_H_ #include <linux/compiler.h> +#include <linux/ieee80211.h> /* * HOST-MAC I/F events @@ -58,7 +59,7 @@ /* * HOST-MAC I/F data structure - * Byte alignmet Little Endian + * Byte alignment Little Endian */ struct hostif_hdr { @@ -224,10 +225,9 @@ struct hostif_start_confirm_t { __le16 result_code; } __packed; -#define SSID_MAX_SIZE 32 struct ssid_t { u8 size; - u8 body[SSID_MAX_SIZE]; + u8 body[IEEE80211_MAX_SSID_LEN]; u8 ssid_pad; } __packed; @@ -284,20 +284,8 @@ struct ap_info_t { u8 pad0; /* +09 */ __le16 beacon_period; /* +10 */ __le16 capability; /* +12 */ -#define BSS_CAP_ESS BIT(0) -#define BSS_CAP_IBSS BIT(1) -#define BSS_CAP_CF_POLABLE BIT(2) -#define BSS_CAP_CF_POLL_REQ BIT(3) -#define BSS_CAP_PRIVACY BIT(4) -#define BSS_CAP_SHORT_PREAMBLE BIT(5) -#define BSS_CAP_PBCC BIT(6) -#define BSS_CAP_CHANNEL_AGILITY BIT(7) -#define BSS_CAP_SHORT_SLOT_TIME BIT(10) -#define BSS_CAP_DSSS_OFDM BIT(13) u8 frame_type; /* +14 */ u8 ch_info; /* +15 */ -#define FRAME_TYPE_BEACON 0x80 -#define FRAME_TYPE_PROBE_RESP 0x50 __le16 body_size; /* +16 */ u8 body[1024]; /* +18 */ /* +1032 */ @@ -347,6 +335,22 @@ struct hostif_stop_confirm_t { __le16 result_code; } __packed; +#define D_11B_ONLY_MODE 0 +#define D_11G_ONLY_MODE 1 +#define D_11BG_COMPATIBLE_MODE 2 +#define D_11A_ONLY_MODE 3 + +#define CTS_MODE_FALSE 0 +#define CTS_MODE_TRUE 1 + +struct hostif_request_t { + __le16 phy_type; + __le16 cts_mode; + __le16 scan_type; + __le16 capability; + struct rate_set16_t rate_set; +} __packed; + /** * struct hostif_ps_adhoc_set_request_t - pseudo adhoc mode * @capability: bit5 : preamble @@ -356,18 +360,8 @@ struct hostif_stop_confirm_t { */ struct hostif_ps_adhoc_set_request_t { struct hostif_hdr header; - __le16 phy_type; -#define D_11B_ONLY_MODE 0 -#define D_11G_ONLY_MODE 1 -#define D_11BG_COMPATIBLE_MODE 2 -#define D_11A_ONLY_MODE 3 - __le16 cts_mode; -#define CTS_MODE_FALSE 0 -#define CTS_MODE_TRUE 1 + struct hostif_request_t request; __le16 channel; - struct rate_set16_t rate_set; - __le16 capability; - __le16 scan_type; } __packed; struct hostif_ps_adhoc_set_confirm_t { @@ -375,48 +369,23 @@ struct hostif_ps_adhoc_set_confirm_t { __le16 result_code; } __packed; -/** - * struct hostif_infrastructure_set_request_t - * @capability: bit5 : preamble - * bit6 : pbcc - Not supported always 0 - * bit10 : ShortSlotTime - * bit13 : DSSS-OFDM - Not supported always 0 - */ -struct hostif_infrastructure_set_request_t { - struct hostif_hdr header; - __le16 phy_type; - __le16 cts_mode; - struct rate_set16_t rate_set; - struct ssid_t ssid; - __le16 capability; - __le16 beacon_lost_count; - __le16 auth_type; #define AUTH_TYPE_OPEN_SYSTEM 0 #define AUTH_TYPE_SHARED_KEY 1 - struct channel_list_t channel_list; - __le16 scan_type; -} __packed; /** - * struct hostif_infrastructure_set2_request_t + * struct hostif_infrastructure_set_request_t * @capability: bit5 : preamble * bit6 : pbcc - Not supported always 0 * bit10 : ShortSlotTime * bit13 : DSSS-OFDM - Not supported always 0 */ -struct hostif_infrastructure_set2_request_t { +struct hostif_infrastructure_set_request_t { struct hostif_hdr header; - __le16 phy_type; - __le16 cts_mode; - struct rate_set16_t rate_set; + struct hostif_request_t request; struct ssid_t ssid; - __le16 capability; __le16 beacon_lost_count; __le16 auth_type; -#define AUTH_TYPE_OPEN_SYSTEM 0 -#define AUTH_TYPE_SHARED_KEY 1 struct channel_list_t channel_list; - __le16 scan_type; u8 bssid[ETH_ALEN]; } __packed; @@ -434,13 +403,9 @@ struct hostif_infrastructure_set_confirm_t { */ struct hostif_adhoc_set_request_t { struct hostif_hdr header; - __le16 phy_type; - __le16 cts_mode; - __le16 channel; - struct rate_set16_t rate_set; + struct hostif_request_t request; struct ssid_t ssid; - __le16 capability; - __le16 scan_type; + __le16 channel; } __packed; /** @@ -452,13 +417,9 @@ struct hostif_adhoc_set_request_t { */ struct hostif_adhoc_set2_request_t { struct hostif_hdr header; - __le16 phy_type; - __le16 cts_mode; + struct hostif_request_t request; __le16 reserved; - struct rate_set16_t rate_set; struct ssid_t ssid; - __le16 capability; - __le16 scan_type; struct channel_list_t channel_list; u8 bssid[ETH_ALEN]; } __packed; @@ -475,8 +436,6 @@ struct last_associate_t { struct association_request_t { u8 type; -#define FRAME_TYPE_ASSOC_REQ 0x00 -#define FRAME_TYPE_REASSOC_REQ 0x20 u8 pad; __le16 capability; __le16 listen_interval; @@ -486,8 +445,6 @@ struct association_request_t { struct association_response_t { u8 type; -#define FRAME_TYPE_ASSOC_RESP 0x10 -#define FRAME_TYPE_REASSOC_RESP 0x30 u8 pad; __le16 capability; __le16 status; diff --git a/drivers/staging/ks7010/ks_wlan.h b/drivers/staging/ks7010/ks_wlan.h index 3767079be00d..1b7036c32d1c 100644 --- a/drivers/staging/ks7010/ks_wlan.h +++ b/drivers/staging/ks7010/ks_wlan.h @@ -34,16 +34,6 @@ #include "ks7010_sdio.h" -#ifdef KS_WLAN_DEBUG -#define DPRINTK(n, fmt, args...) \ - do { \ - if (KS_WLAN_DEBUG > (n)) \ - pr_notice("%s: "fmt, __func__, ## args); \ - } while (0) -#else -#define DPRINTK(n, fmt, args...) -#endif - struct ks_wlan_parameter { u8 operation_mode; /* Operation Mode */ u8 channel; /* Channel */ @@ -64,7 +54,7 @@ struct ks_wlan_parameter { #define BEACON_LOST_COUNT_MAX 65535 u32 beacon_lost_count; /* Beacon Lost Count */ u32 rts; /* RTS Threashold */ - u32 fragment; /* Fragmentation Threashold */ + u32 fragment; /* Fragmentation Threshold */ u32 privacy_invoked; u32 wep_index; struct { @@ -97,7 +87,7 @@ enum { #define SME_WEP_VAL2 BIT(6) #define SME_WEP_VAL3 BIT(7) #define SME_WEP_VAL4 BIT(8) -#define SME_WEP_VAL_MASK (SME_WEP_VAL1 | SME_WEP_VAL2 | SME_WEP_VAL3 | SME_WEP_VAL4) +#define SME_WEP_VAL_MASK GENMASK(8, 5) #define SME_RSN BIT(9) #define SME_RSN_MULTICAST BIT(10) #define SME_RSN_UNICAST BIT(11) @@ -202,10 +192,6 @@ struct sme_info { int event_buff[SME_EVENT_BUFF_SIZE]; unsigned int qhead; unsigned int qtail; -#ifdef KS_WLAN_DEBUG - /* for debug */ - unsigned int max_event_count; -#endif spinlock_t sme_spin; unsigned long sme_flag; }; @@ -420,7 +406,6 @@ struct ks_wlan_private { struct tasklet_struct rx_bh_task; struct net_device *net_dev; - int reg_net; /* register_netdev */ struct net_device_stats nstats; struct iw_statistics wstats; @@ -470,7 +455,7 @@ struct ks_wlan_private { unsigned char firmware_version[128 + 1]; int version_size; - int mac_address_valid; /* Mac Address Status */ + bool mac_address_valid; /* Mac Address Status */ int dev_state; diff --git a/drivers/staging/ks7010/ks_wlan_ioctl.h b/drivers/staging/ks7010/ks_wlan_ioctl.h index 28b381c24b42..121e7cb808a2 100644 --- a/drivers/staging/ks7010/ks_wlan_ioctl.h +++ b/drivers/staging/ks7010/ks_wlan_ioctl.h @@ -58,7 +58,6 @@ #include "ks_wlan.h" #include <linux/netdevice.h> -int ks_wlan_read_config_file(struct ks_wlan_private *priv); int ks_wlan_setup_parameter(struct ks_wlan_private *priv, unsigned int commit_flag); diff --git a/drivers/staging/ks7010/ks_wlan_net.c b/drivers/staging/ks7010/ks_wlan_net.c index e48c55769c94..9078e13b0d4a 100644 --- a/drivers/staging/ks7010/ks_wlan_net.c +++ b/drivers/staging/ks7010/ks_wlan_net.c @@ -86,7 +86,7 @@ int ks_wlan_update_phy_information(struct ks_wlan_private *priv) { struct iw_statistics *wstats = &priv->wstats; - DPRINTK(4, "in_interrupt = %ld\n", in_interrupt()); + netdev_dbg(priv->net_dev, "in_interrupt = %ld\n", in_interrupt()); if (priv->dev_state < DEVICE_STATE_READY) return -EBUSY; /* not finished initialize */ @@ -103,7 +103,7 @@ int ks_wlan_update_phy_information(struct ks_wlan_private *priv) /* interruptible_sleep_on_timeout(&priv->confirm_wait, HZ/2); */ if (!wait_for_completion_interruptible_timeout (&priv->confirm_wait, HZ / 2)) { - DPRINTK(1, "wait time out!!\n"); + netdev_dbg(priv->net_dev, "wait time out!!\n"); } atomic_inc(&update_phyinfo); @@ -116,15 +116,13 @@ int ks_wlan_update_phy_information(struct ks_wlan_private *priv) static void ks_wlan_update_phyinfo_timeout(struct timer_list *unused) { - DPRINTK(4, "in_interrupt = %ld\n", in_interrupt()); + pr_debug("in_interrupt = %ld\n", in_interrupt()); atomic_set(&update_phyinfo, 0); } int ks_wlan_setup_parameter(struct ks_wlan_private *priv, unsigned int commit_flag) { - DPRINTK(2, "\n"); - hostif_sme_enqueue(priv, SME_STOP_REQUEST); if (commit_flag & SME_RTS) @@ -268,8 +266,6 @@ static int ks_wlan_set_essid(struct net_device *dev, struct ks_wlan_private *priv = netdev_priv(dev); size_t len; - DPRINTK(2, " %d\n", dwrq->flags); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -280,7 +276,6 @@ static int ks_wlan_set_essid(struct net_device *dev, memset(priv->reg.ssid.body, 0, sizeof(priv->reg.ssid.body)); priv->reg.ssid.size = 0; } else { -#if 1 len = dwrq->length; /* iwconfig uses nul termination in SSID.. */ if (len > 0 && extra[len - 1] == '\0') @@ -290,28 +285,14 @@ static int ks_wlan_set_essid(struct net_device *dev, if (len > IW_ESSID_MAX_SIZE) return -EINVAL; -#else - /* Check the size of the string */ - if (dwrq->length > IW_ESSID_MAX_SIZE + 1) - return -E2BIG; - -#endif - /* Set the SSID */ memset(priv->reg.ssid.body, 0, sizeof(priv->reg.ssid.body)); - -#if 1 memcpy(priv->reg.ssid.body, extra, len); priv->reg.ssid.size = len; -#else - memcpy(priv->reg.ssid.body, extra, dwrq->length); - priv->reg.ssid.size = dwrq->length; -#endif } /* Write it to the card */ priv->need_commit |= SME_MODE_SET; -// return -EINPROGRESS; /* Call commit handler */ ks_wlan_setup_parameter(priv, priv->need_commit); priv->need_commit = 0; return 0; @@ -352,8 +333,6 @@ static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -370,7 +349,7 @@ static int ks_wlan_set_wap(struct net_device *dev, struct iw_request_info *info, return -EOPNOTSUPP; } - DPRINTK(2, "bssid = %pM\n", priv->reg.bssid); + netdev_dbg(dev, "bssid = %pM\n", priv->reg.bssid); /* Write it to the card */ if (priv->need_commit) { @@ -683,8 +662,8 @@ static int ks_wlan_get_rate(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "in_interrupt = %ld update_phyinfo = %d\n", - in_interrupt(), atomic_read(&update_phyinfo)); + netdev_dbg(dev, "in_interrupt = %ld update_phyinfo = %d\n", + in_interrupt(), atomic_read(&update_phyinfo)); if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -785,8 +764,6 @@ static int ks_wlan_set_mode(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "mode=%d\n", *uwrq); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -848,8 +825,6 @@ static int ks_wlan_set_encode(struct net_device *dev, int current_index = priv->reg.wep_index; int i; - DPRINTK(2, "flags=%04X\n", dwrq->flags); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -986,7 +961,6 @@ static int ks_wlan_get_encode(struct net_device *dev, /* dwrq->flags |= IW_ENCODE_NOKEY; */ } dwrq->flags |= index + 1; - DPRINTK(2, "encoding flag = 0x%04X\n", dwrq->flags); /* Copy the key to the user buffer */ if ((index >= 0) && (index < 4)) dwrq->length = priv->reg.wep_key[index].size; @@ -1058,8 +1032,6 @@ static int ks_wlan_get_range(struct net_device *dev, struct iw_range *range = (struct iw_range *)extra; int i, k; - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -1300,8 +1272,6 @@ static int ks_wlan_set_scan(struct net_device *dev, struct ks_wlan_private *priv = netdev_priv(dev); struct iw_scan_req *req = NULL; - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -1366,8 +1336,8 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, /* Add mode */ iwe.cmd = SIOCGIWMODE; capabilities = ap->capability; - if (capabilities & (BSS_CAP_ESS | BSS_CAP_IBSS)) { - if (capabilities & BSS_CAP_ESS) + if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (capabilities & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_INFRA; else iwe.u.mode = IW_MODE_ADHOC; @@ -1396,7 +1366,7 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; - if (capabilities & BSS_CAP_PRIVACY) + if (capabilities & WLAN_CAPABILITY_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; @@ -1450,7 +1420,7 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, pbuf += sprintf(pbuf, "%02x", ap->rsn_ie.body[i]); iwe.u.data.length += (ap->rsn_ie.size) * 2; - DPRINTK(4, "ap->rsn.size=%d\n", ap->rsn_ie.size); + netdev_dbg(dev, "ap->rsn.size=%d\n", ap->rsn_ie.size); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, @@ -1472,8 +1442,8 @@ static inline char *ks_wlan_translate_scan(struct net_device *dev, pbuf += sprintf(pbuf, "%02x", ap->wpa_ie.body[i]); iwe.u.data.length += (ap->wpa_ie.size) * 2; - DPRINTK(4, "ap->rsn.size=%d\n", ap->wpa_ie.size); - DPRINTK(4, "iwe.u.data.length=%d\n", iwe.u.data.length); + netdev_dbg(dev, "ap->rsn.size=%d\n", ap->wpa_ie.size); + netdev_dbg(dev, "iwe.u.data.length=%d\n", iwe.u.data.length); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, @@ -1494,21 +1464,16 @@ static int ks_wlan_get_scan(struct net_device *dev, int i; char *current_ev = extra; - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; /* for SLEEP MODE */ - if (priv->sme_i.sme_flag & SME_AP_SCAN) { - DPRINTK(2, "flag AP_SCAN\n"); + if (priv->sme_i.sme_flag & SME_AP_SCAN) return -EAGAIN; - } if (priv->aplist.size == 0) { /* Client error, no scan results... * The caller need to restart the scan. */ - DPRINTK(2, "aplist 0\n"); return -ENODATA; } @@ -1552,8 +1517,6 @@ static int ks_wlan_set_genie(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; /* for SLEEP MODE */ @@ -1569,8 +1532,6 @@ static int ks_wlan_set_auth_mode(struct net_device *dev, int index = (vwrq->flags & IW_AUTH_INDEX); int value = vwrq->value; - DPRINTK(2, "index=%d:value=%08X\n", index, value); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; /* for SLEEP MODE */ @@ -1702,8 +1663,6 @@ static int ks_wlan_get_auth_mode(struct net_device *dev, struct ks_wlan_private *priv = netdev_priv(dev); int index = (vwrq->flags & IW_AUTH_INDEX); - DPRINTK(2, "index=%d\n", index); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -1753,9 +1712,6 @@ static int ks_wlan_set_encode_ext(struct net_device *dev, if (!enc) return -EINVAL; - DPRINTK(2, "flags=%04X:: ext_flags=%08X\n", dwrq->flags, - enc->ext_flags); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -1865,8 +1821,6 @@ static int ks_wlan_set_pmksa(struct net_device *dev, struct pmk_t *pmk; struct list_head *ptr; - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -1875,7 +1829,6 @@ static int ks_wlan_set_pmksa(struct net_device *dev, return -EINVAL; pmksa = (struct iw_pmksa *)extra; - DPRINTK(2, "cmd=%d\n", pmksa->cmd); switch (pmksa->cmd) { case IW_PMKSA_ADD: @@ -1987,8 +1940,6 @@ static int ks_wlan_set_stop_request(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -2009,8 +1960,6 @@ static int ks_wlan_set_mlme(struct net_device *dev, struct iw_mlme *mlme = (struct iw_mlme *)extra; __u32 mode; - DPRINTK(2, ":%d :%d\n", mlme->cmd, mlme->reason_code); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; @@ -2269,8 +2218,6 @@ static int ks_wlan_set_sleep_mode(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "\n"); - if (*uwrq == SLP_SLEEP) { priv->sleep_mode = *uwrq; netdev_info(dev, "SET_SLEEP_MODE %d\n", priv->sleep_mode); @@ -2296,7 +2243,6 @@ static int ks_wlan_get_sleep_mode(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "GET_SLEEP_MODE %d\n", priv->sleep_mode); *uwrq = priv->sleep_mode; return 0; @@ -2310,8 +2256,6 @@ static int ks_wlan_set_wps_enable(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; /* for SLEEP MODE */ @@ -2331,8 +2275,6 @@ static int ks_wlan_get_wps_enable(struct net_device *dev, { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; /* for SLEEP MODE */ @@ -2350,12 +2292,8 @@ static int ks_wlan_set_wps_probe_req(struct net_device *dev, unsigned char len; struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(2, "\n"); - if (priv->sleep_mode == SLP_SLEEP) return -EPERM; - /* for SLEEP MODE */ - DPRINTK(2, "dwrq->length=%d\n", dwrq->length); /* length check */ if (p[1] + 2 != dwrq->length || dwrq->length > 256) @@ -2367,10 +2305,10 @@ static int ks_wlan_set_wps_probe_req(struct net_device *dev, memcpy(priv->wps.ie, &len, sizeof(len)); p = memcpy(priv->wps.ie + 1, p, len); - DPRINTK(2, "%d(%#x): %02X %02X %02X %02X ... %02X %02X %02X\n", - priv->wps.ielen, priv->wps.ielen, p[0], p[1], p[2], p[3], - p[priv->wps.ielen - 3], p[priv->wps.ielen - 2], - p[priv->wps.ielen - 1]); + netdev_dbg(dev, "%d(%#x): %02X %02X %02X %02X ... %02X %02X %02X\n", + priv->wps.ielen, priv->wps.ielen, p[0], p[1], p[2], p[3], + p[priv->wps.ielen - 3], p[priv->wps.ielen - 2], + p[priv->wps.ielen - 1]); hostif_sme_enqueue(priv, SME_WPS_PROBE_REQUEST); @@ -2789,7 +2727,6 @@ static int ks_wlan_netdev_ioctl(struct net_device *dev, struct ifreq *rq, ret = -EOPNOTSUPP; } - DPRINTK(5, "return=%d\n", ret); return ret; } @@ -2815,7 +2752,7 @@ int ks_wlan_set_mac_address(struct net_device *dev, void *addr) memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len); memcpy(priv->eth_addr, mac_addr->sa_data, ETH_ALEN); - priv->mac_address_valid = 0; + priv->mac_address_valid = false; hostif_sme_enqueue(priv, SME_MACADDRESS_SET_REQUEST); netdev_info(dev, "ks_wlan: MAC ADDRESS = %pM\n", priv->eth_addr); return 0; @@ -2826,8 +2763,8 @@ void ks_wlan_tx_timeout(struct net_device *dev) { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(1, "head(%d) tail(%d)!!\n", priv->tx_dev.qhead, - priv->tx_dev.qtail); + netdev_dbg(dev, "head(%d) tail(%d)!!\n", priv->tx_dev.qhead, + priv->tx_dev.qtail); if (!netif_queue_stopped(dev)) netif_stop_queue(dev); priv->nstats.tx_errors++; @@ -2840,7 +2777,7 @@ int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev) struct ks_wlan_private *priv = netdev_priv(dev); int ret; - DPRINTK(3, "in_interrupt()=%ld\n", in_interrupt()); + netdev_dbg(dev, "in_interrupt()=%ld\n", in_interrupt()); if (!skb) { netdev_err(dev, "ks_wlan: skb == NULL!!!\n"); @@ -2858,15 +2795,13 @@ int ks_wlan_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_trans_update(dev); if (ret) - DPRINTK(4, "hostif_data_request error: =%d\n", ret); + netdev_err(dev, "hostif_data_request error: =%d\n", ret); return 0; } void send_packet_complete(struct ks_wlan_private *priv, struct sk_buff *skb) { - DPRINTK(3, "\n"); - priv->nstats.tx_packets++; if (netif_queue_stopped(priv->net_dev)) @@ -2887,7 +2822,6 @@ void ks_wlan_set_multicast_list(struct net_device *dev) { struct ks_wlan_private *priv = netdev_priv(dev); - DPRINTK(4, "\n"); if (priv->dev_state < DEVICE_STATE_READY) return; /* not finished initialize */ hostif_sme_enqueue(priv, SME_MULTICAST_REQUEST); @@ -2914,9 +2848,6 @@ int ks_wlan_close(struct net_device *dev) { netif_stop_queue(dev); - DPRINTK(4, "%s: Shutting down ethercard, status was 0x%4.4x.\n", - dev->name, 0x00); - return 0; } @@ -2944,7 +2875,7 @@ int ks_wlan_net_start(struct net_device *dev) /* int rc; */ priv = netdev_priv(dev); - priv->mac_address_valid = 0; + priv->mac_address_valid = false; priv->need_commit = 0; priv->device_open_status = 1; @@ -2966,7 +2897,7 @@ int ks_wlan_net_start(struct net_device *dev) /* The ks_wlan-specific entries in the device structure. */ dev->netdev_ops = &ks_wlan_netdev_ops; - dev->wireless_handlers = (struct iw_handler_def *)&ks_wlan_handler_def; + dev->wireless_handlers = &ks_wlan_handler_def; dev->watchdog_timeo = TX_TIMEOUT; netif_carrier_off(dev); diff --git a/drivers/staging/ks7010/michael_mic.c b/drivers/staging/ks7010/michael_mic.c index 80497ef5b1aa..292eae29c552 100644 --- a/drivers/staging/ks7010/michael_mic.c +++ b/drivers/staging/ks7010/michael_mic.c @@ -11,123 +11,107 @@ #include <linux/types.h> #include <linux/string.h> +#include <linux/bitops.h> +#include <asm/unaligned.h> #include "michael_mic.h" -// Rotation functions on 32 bit values -#define ROL32(A, n) (((A) << (n)) | (((A) >> (32 - (n))) & ((1UL << (n)) - 1))) -#define ROR32(A, n) ROL32((A), 32 - (n)) -// Convert from Byte[] to UInt32 in a portable way -#define getUInt32(A, B) ((uint32_t)(A[B + 0] << 0) \ - + (A[B + 1] << 8) + (A[B + 2] << 16) + (A[B + 3] << 24)) - -// Convert from UInt32 to Byte[] in a portable way -#define putUInt32(A, B, C) \ -do { \ - A[B + 0] = (uint8_t)(C & 0xff); \ - A[B + 1] = (uint8_t)((C >> 8) & 0xff); \ - A[B + 2] = (uint8_t)((C >> 16) & 0xff); \ - A[B + 3] = (uint8_t)((C >> 24) & 0xff); \ -} while (0) // Reset the state to the empty message. -#define MichaelClear(A) \ -do { \ - A->L = A->K0; \ - A->R = A->K1; \ - A->nBytesInM = 0; \ -} while (0) - -static -void MichaelInitializeFunction(struct michael_mic_t *Mic, uint8_t *key) +static inline void michael_clear(struct michael_mic_t *mic) +{ + mic->l = mic->k0; + mic->r = mic->k1; + mic->m_bytes = 0; +} + +static void michael_init(struct michael_mic_t *mic, u8 *key) { // Set the key - Mic->K0 = getUInt32(key, 0); - Mic->K1 = getUInt32(key, 4); + mic->k0 = get_unaligned_le32(key); + mic->k1 = get_unaligned_le32(key + 4); //clear(); - MichaelClear(Mic); + michael_clear(mic); +} + +static inline void michael_block(struct michael_mic_t *mic) +{ + mic->r ^= rol32(mic->l, 17); + mic->l += mic->r; + mic->r ^= ((mic->l & 0xff00ff00) >> 8) | + ((mic->l & 0x00ff00ff) << 8); + mic->l += mic->r; + mic->r ^= rol32(mic->l, 3); \ + mic->l += mic->r; + mic->r ^= ror32(mic->l, 2); \ + mic->l += mic->r; } -#define MichaelBlockFunction(L, R) \ -do { \ - R ^= ROL32(L, 17); \ - L += R; \ - R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); \ - L += R; \ - R ^= ROL32(L, 3); \ - L += R; \ - R ^= ROR32(L, 2); \ - L += R; \ -} while (0) - -static -void MichaelAppend(struct michael_mic_t *Mic, uint8_t *src, int nBytes) +static void michael_append(struct michael_mic_t *mic, u8 *src, int bytes) { int addlen; - if (Mic->nBytesInM) { - addlen = 4 - Mic->nBytesInM; - if (addlen > nBytes) - addlen = nBytes; - memcpy(&Mic->M[Mic->nBytesInM], src, addlen); - Mic->nBytesInM += addlen; + if (mic->m_bytes) { + addlen = 4 - mic->m_bytes; + if (addlen > bytes) + addlen = bytes; + memcpy(&mic->m[mic->m_bytes], src, addlen); + mic->m_bytes += addlen; src += addlen; - nBytes -= addlen; + bytes -= addlen; - if (Mic->nBytesInM < 4) + if (mic->m_bytes < 4) return; - Mic->L ^= getUInt32(Mic->M, 0); - MichaelBlockFunction(Mic->L, Mic->R); - Mic->nBytesInM = 0; + mic->l ^= get_unaligned_le32(mic->m); + michael_block(mic); + mic->m_bytes = 0; } - while (nBytes >= 4) { - Mic->L ^= getUInt32(src, 0); - MichaelBlockFunction(Mic->L, Mic->R); + while (bytes >= 4) { + mic->l ^= get_unaligned_le32(src); + michael_block(mic); src += 4; - nBytes -= 4; + bytes -= 4; } - if (nBytes > 0) { - Mic->nBytesInM = nBytes; - memcpy(Mic->M, src, nBytes); + if (bytes > 0) { + mic->m_bytes = bytes; + memcpy(mic->m, src, bytes); } } -static -void MichaelGetMIC(struct michael_mic_t *Mic, uint8_t *dst) +static void michael_get_mic(struct michael_mic_t *mic, u8 *dst) { - u8 *data = Mic->M; + u8 *data = mic->m; - switch (Mic->nBytesInM) { + switch (mic->m_bytes) { case 0: - Mic->L ^= 0x5a; + mic->l ^= 0x5a; break; case 1: - Mic->L ^= data[0] | 0x5a00; + mic->l ^= data[0] | 0x5a00; break; case 2: - Mic->L ^= data[0] | (data[1] << 8) | 0x5a0000; + mic->l ^= data[0] | (data[1] << 8) | 0x5a0000; break; case 3: - Mic->L ^= data[0] | (data[1] << 8) | (data[2] << 16) | + mic->l ^= data[0] | (data[1] << 8) | (data[2] << 16) | 0x5a000000; break; } - MichaelBlockFunction(Mic->L, Mic->R); - MichaelBlockFunction(Mic->L, Mic->R); + michael_block(mic); + michael_block(mic); // The appendByte function has already computed the result. - putUInt32(dst, 0, Mic->L); - putUInt32(dst, 4, Mic->R); + put_unaligned_le32(mic->l, dst); + put_unaligned_le32(mic->r, dst + 4); // Reset to the empty message. - MichaelClear(Mic); + michael_clear(mic); } -void MichaelMICFunction(struct michael_mic_t *Mic, u8 *Key, - u8 *Data, int Len, u8 priority, - u8 *Result) +void michael_mic_function(struct michael_mic_t *mic, u8 *key, + u8 *data, int len, u8 priority, u8 *result) { u8 pad_data[4] = { priority, 0, 0, 0 }; // Compute the MIC value @@ -140,9 +124,9 @@ void MichaelMICFunction(struct michael_mic_t *Mic, u8 *Key, * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7| * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ */ - MichaelInitializeFunction(Mic, Key); - MichaelAppend(Mic, (uint8_t *)Data, 12); /* |DA|SA| */ - MichaelAppend(Mic, pad_data, 4); /* |Priority|0|0|0| */ - MichaelAppend(Mic, (uint8_t *)(Data + 12), Len - 12); /* |Data| */ - MichaelGetMIC(Mic, Result); + michael_init(mic, key); + michael_append(mic, data, 12); /* |DA|SA| */ + michael_append(mic, pad_data, 4); /* |Priority|0|0|0| */ + michael_append(mic, data + 12, len - 12); /* |Data| */ + michael_get_mic(mic, result); } diff --git a/drivers/staging/ks7010/michael_mic.h b/drivers/staging/ks7010/michael_mic.h index 758e429446f1..894a8d4121a4 100644 --- a/drivers/staging/ks7010/michael_mic.h +++ b/drivers/staging/ks7010/michael_mic.h @@ -11,15 +11,14 @@ /* MichaelMIC routine define */ struct michael_mic_t { - u32 K0; // Key - u32 K1; // Key - u32 L; // Current state - u32 R; // Current state - u8 M[4]; // Message accumulator (single word) - int nBytesInM; // # bytes in M - u8 Result[8]; + u32 k0; // Key + u32 k1; // Key + u32 l; // Current state + u32 r; // Current state + u8 m[4]; // Message accumulator (single word) + int m_bytes; // # bytes in M + u8 result[8]; }; -void MichaelMICFunction(struct michael_mic_t *Mic, u8 *Key, - u8 *Data, int Len, u8 priority, - u8 *Result); +void michael_mic_function(struct michael_mic_t *mic, u8 *key, + u8 *data, int len, u8 priority, u8 *result); diff --git a/drivers/staging/lustre/TODO b/drivers/staging/lustre/TODO index f194417d0af7..94446487748a 100644 --- a/drivers/staging/lustre/TODO +++ b/drivers/staging/lustre/TODO @@ -1,12 +1,302 @@ -* Possible remaining coding style fix. -* Remove deadcode. -* Separate client/server functionality. Functions only used by server can be - removed from client. -* Clean up libcfs layer. Ideally we can remove include/linux/libcfs entirely. -* Clean up CLIO layer. Lustre client readahead/writeback control needs to better - suit kernel providings. -* Add documents in Documentation. -* Other minor misc cleanups... +Currently all the work directed toward the lustre upstream client is tracked +at the following link: + +https://jira.hpdd.intel.com/browse/LU-9679 + +Under this ticket you will see the following work items that need to be +addressed: + +****************************************************************************** +* libcfs cleanup +* +* https://jira.hpdd.intel.com/browse/LU-9859 +* +* Track all the cleanups and simplification of the libcfs module. Remove +* functions the kernel provides. Possible intergrate some of the functionality +* into the kernel proper. +* +****************************************************************************** + +https://jira.hpdd.intel.com/browse/LU-100086 + +LNET_MINOR conflicts with USERIO_MINOR + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8130 + +Fix and simplify libcfs hash handling + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8703 + +The current way we handle SMP is wrong. Platforms like ARM and KNL can have +core and NUMA setups with things like NUMA nodes with no cores. We need to +handle such cases. This work also greatly simplified the lustre SMP code. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9019 + +Replace libcfs time API with standard kernel APIs. Also migrate away from +jiffies. We found jiffies can vary on nodes which can lead to corner cases +that can break the file system due to nodes having inconsistent behavior. +So move to time64_t and ktime_t as much as possible. + +****************************************************************************** +* Proper IB support for ko2iblnd +****************************************************************************** +https://jira.hpdd.intel.com/browse/LU-9179 + +Poor performance for the ko2iblnd driver. This is related to many of the +patches below that are missing from the linux client. +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9886 + +Crash in upstream kiblnd_handle_early_rxs() +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10394 / LU-10526 / LU-10089 + +Default to default to using MEM_REG +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10459 + +throttle tx based on queue depth +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9943 + +correct WR fast reg accounting +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10291 + +remove concurrent_sends tunable +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10213 + +calculate qp max_send_wrs properly +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9810 + +use less CQ entries for each connection +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10129 / LU-9180 + +rework map_on_demand behavior +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10129 + +query device capabilities +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10015 + +fix race at kiblnd_connect_peer +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9983 + +allow for discontiguous fragments +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9500 + +Don't Page Align remote_addr with FastReg +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9448 + +handle empty CPTs +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9507 + +Don't Assert On Reconnect with MultiQP +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9472 + +Fix FastReg map/unmap for MLX5 +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9425 + +Turn on 2 sges by default +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8943 + +Enable Multiple OPA Endpoints between Nodes +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-5718 + +multiple sges for work request +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9094 + +kill timedout txs from ibp_tx_queue +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9094 + +reconnect peer for REJ_INVALID_SERVICE_ID +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8752 + +Stop MLX5 triggering a dump_cqe +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8874 + +Move ko2iblnd to latest RDMA changes +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8875 / LU-8874 + +Change to new RDMA done callback mechanism + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9164 / LU-8874 + +Incorporate RDMA map/unamp API's into ko2iblnd + +****************************************************************************** +* sysfs/debugfs fixes +* +* https://jira.hpdd.intel.com/browse/LU-8066 +* +* The original migration to sysfs was done in haste without properly working +* utilities to test the changes. This covers the work to restore the proper +* behavior. Huge project to make this right. +* +****************************************************************************** + +https://jira.hpdd.intel.com/browse/LU-9431 + +The function class_process_proc_param was used for our mass updates of proc +tunables. It didn't work with sysfs and it was just ugly so it was removed. +In the process the ability to mass update thousands of clients was lost. This +work restores this in a sane way. + +------------------------------------------------------------------------------ +https://jira.hpdd.intel.com/browse/LU-9091 + +One the major request of users is the ability to pass in parameters into a +sysfs file in various different units. For example we can set max_pages_per_rpc +but this can vary on platforms due to different platform sizes. So you can +set this like max_pages_per_rpc=16MiB. The original code to handle this written +before the string helpers were created so the code doesn't follow that format +but it would be easy to move to. Currently the string helpers does the reverse +of what we need, changing bytes to string. We need to change a string to bytes. + +****************************************************************************** +* Proper user land to kernel space interface for Lustre +* +* https://jira.hpdd.intel.com/browse/LU-9680 +* +****************************************************************************** + +https://jira.hpdd.intel.com/browse/LU-8915 + +Don't use linux list structure as user land arguments for lnet selftest. +This code is pretty poor quality and really needs to be reworked. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8834 + +The lustre ioctl LL_IOC_FUTIMES_3 is very generic. Need to either work with +other file systems with similar functionality and make a common syscall +interface or rework our server code to automagically do it for us. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-6202 + +Cleanup up ioctl handling. We have many obsolete ioctls. Also the way we do +ioctls can be changed over to netlink. This also has the benefit of working +better with HPC systems that do IO forwarding. Such systems don't like ioctls +very well. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9667 + +More cleanups by making our utilities use sysfs instead of ioctls for LNet. +Also it has been requested to move the remaining ioctls to the netlink API. + +****************************************************************************** +* Misc +****************************************************************************** + +------------------------------------------------------------------------------ +https://jira.hpdd.intel.com/browse/LU-9855 + +Clean up obdclass preprocessor code. One of the major eye sores is the various +pointer redirections and macros used by the obdclass. This makes the code very +difficult to understand. It was requested by the Al Viro to clean this up before +we leave staging. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9633 + +Migrate to sphinx kernel-doc style comments. Add documents in Documentation. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-6142 + +Possible remaining coding style fix. Remove deadcode. Enforce kernel code +style. Other minor misc cleanups... + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8837 + +Separate client/server functionality. Functions only used by server can be +removed from client. Most of this has been done but we need a inspect of the +code to make sure. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-8964 + +Lustre client readahead/writeback control needs to better suit kernel providings. +Currently its being explored. We could end up replacing the CLIO read ahead +abstract with the kernel proper version. + +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9862 + +Patch that landed for LU-7890 leads to static checker errors +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-9868 + +dcache/namei fixes for lustre +------------------------------------------------------------------------------ + +https://jira.hpdd.intel.com/browse/LU-10467 + +use standard linux wait_events macros work by Neil Brown + +------------------------------------------------------------------------------ Please send any patches to Greg Kroah-Hartman <greg@kroah.com>, Andreas Dilger -<andreas.dilger@intel.com>, and Oleg Drokin <oleg.drokin@intel.com>. +<andreas.dilger@intel.com>, James Simmons <jsimmons@infradead.org> and +Oleg Drokin <oleg.drokin@intel.com>. diff --git a/drivers/staging/lustre/include/linux/libcfs/curproc.h b/drivers/staging/lustre/include/linux/libcfs/curproc.h index 3cb3f086148e..4702956805a6 100644 --- a/drivers/staging/lustre/include/linux/libcfs/curproc.h +++ b/drivers/staging/lustre/include/linux/libcfs/curproc.h @@ -56,30 +56,21 @@ typedef u32 cfs_cap_t; -#define CFS_CAP_CHOWN 0 -#define CFS_CAP_DAC_OVERRIDE 1 -#define CFS_CAP_DAC_READ_SEARCH 2 -#define CFS_CAP_FOWNER 3 -#define CFS_CAP_FSETID 4 -#define CFS_CAP_LINUX_IMMUTABLE 9 -#define CFS_CAP_SYS_ADMIN 21 -#define CFS_CAP_SYS_BOOT 23 -#define CFS_CAP_SYS_RESOURCE 24 +#define CFS_CAP_FS_MASK (BIT(CAP_CHOWN) | \ + BIT(CAP_DAC_OVERRIDE) | \ + BIT(CAP_DAC_READ_SEARCH) | \ + BIT(CAP_FOWNER) | \ + BIT(CAP_FSETID) | \ + BIT(CAP_LINUX_IMMUTABLE) | \ + BIT(CAP_SYS_ADMIN) | \ + BIT(CAP_SYS_BOOT) | \ + BIT(CAP_SYS_RESOURCE)) -#define CFS_CAP_FS_MASK (BIT(CFS_CAP_CHOWN) | \ - BIT(CFS_CAP_DAC_OVERRIDE) | \ - BIT(CFS_CAP_DAC_READ_SEARCH) | \ - BIT(CFS_CAP_FOWNER) | \ - BIT(CFS_CAP_FSETID) | \ - BIT(CFS_CAP_LINUX_IMMUTABLE) | \ - BIT(CFS_CAP_SYS_ADMIN) | \ - BIT(CFS_CAP_SYS_BOOT) | \ - BIT(CFS_CAP_SYS_RESOURCE)) - -void cfs_cap_raise(cfs_cap_t cap); -void cfs_cap_lower(cfs_cap_t cap); -int cfs_cap_raised(cfs_cap_t cap); -cfs_cap_t cfs_curproc_cap_pack(void); +static inline cfs_cap_t cfs_curproc_cap_pack(void) +{ + /* cfs_cap_t is only the first word of kernel_cap_t */ + return (cfs_cap_t)(current_cap().cap[0]); +} /* __LIBCFS_CURPROC_H__ */ #endif diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h index ca3472cc952f..392793582956 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h @@ -64,14 +64,21 @@ #define LNET_ACCEPTOR_MIN_RESERVED_PORT 512 #define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023 -/* - * Defined by platform - */ -sigset_t cfs_block_allsigs(void); -sigset_t cfs_block_sigs(unsigned long sigs); -sigset_t cfs_block_sigsinv(unsigned long sigs); -void cfs_restore_sigs(sigset_t sigset); -void cfs_clear_sigpending(void); +/* Block all signals except for the @sigs */ +static inline void cfs_block_sigsinv(unsigned long sigs, sigset_t *old) +{ + sigset_t new; + + siginitsetinv(&new, sigs); + sigorsets(&new, ¤t->blocked, &new); + sigprocmask(SIG_BLOCK, &new, old); +} + +static inline void +cfs_restore_sigs(sigset_t *old) +{ + sigprocmask(SIG_SETMASK, old, NULL); +} struct libcfs_ioctl_handler { struct list_head item; @@ -105,10 +112,6 @@ static inline void *__container_of(void *ptr, unsigned long shift) #define _LIBCFS_H -void *libcfs_kvzalloc(size_t size, gfp_t flags); -void *libcfs_kvzalloc_cpt(struct cfs_cpt_table *cptab, int cpt, size_t size, - gfp_t flags); - extern struct miscdevice libcfs_dev; /** * The path of debug log dump upcall script. diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h index e5c156e9d907..3a72117140ed 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_crypto.h @@ -189,18 +189,15 @@ int cfs_crypto_hash_digest(enum cfs_crypto_hash_alg hash_alg, unsigned char *key, unsigned int key_len, unsigned char *hash, unsigned int *hash_len); -/* cfs crypto hash descriptor */ -struct cfs_crypto_hash_desc; - -struct cfs_crypto_hash_desc * +struct ahash_request * cfs_crypto_hash_init(enum cfs_crypto_hash_alg hash_alg, unsigned char *key, unsigned int key_len); -int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *desc, +int cfs_crypto_hash_update_page(struct ahash_request *desc, struct page *page, unsigned int offset, unsigned int len); -int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *desc, const void *buf, +int cfs_crypto_hash_update(struct ahash_request *desc, const void *buf, unsigned int buf_len); -int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *desc, +int cfs_crypto_hash_final(struct ahash_request *desc, unsigned char *hash, unsigned int *hash_len); int cfs_crypto_register(void); void cfs_crypto_unregister(void); diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h index 1b98f0953afb..9290a19429e7 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h @@ -66,8 +66,8 @@ extern unsigned int libcfs_panic_on_lbug; # define DEBUG_SUBSYSTEM S_UNDEFINED #endif -#define CDEBUG_DEFAULT_MAX_DELAY (cfs_time_seconds(600)) /* jiffies */ -#define CDEBUG_DEFAULT_MIN_DELAY ((cfs_time_seconds(1) + 1) / 2) /* jiffies */ +#define CDEBUG_DEFAULT_MAX_DELAY (600 * HZ) /* jiffies */ +#define CDEBUG_DEFAULT_MIN_DELAY ((HZ + 1) / 2) /* jiffies */ #define CDEBUG_DEFAULT_BACKOFF 2 struct cfs_debug_limit_state { unsigned long cdls_next; diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h index 9699646decb9..c4f25be78268 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_time.h @@ -62,7 +62,7 @@ static inline int cfs_time_aftereq(unsigned long t1, unsigned long t2) static inline unsigned long cfs_time_shift(int seconds) { - return cfs_time_add(cfs_time_current(), cfs_time_seconds(seconds)); + return cfs_time_add(cfs_time_current(), seconds * HZ); } /* diff --git a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h index aece13698eb4..805cb326af86 100644 --- a/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h +++ b/drivers/staging/lustre/include/linux/libcfs/linux/linux-time.h @@ -65,11 +65,6 @@ static inline unsigned long cfs_time_current(void) return jiffies; } -static inline long cfs_time_seconds(int seconds) -{ - return ((long)seconds) * msecs_to_jiffies(MSEC_PER_SEC); -} - static inline long cfs_duration_sec(long d) { return d / msecs_to_jiffies(MSEC_PER_SEC); @@ -85,7 +80,7 @@ static inline u64 cfs_time_add_64(u64 t, u64 d) static inline u64 cfs_time_shift_64(int seconds) { return cfs_time_add_64(cfs_time_current_64(), - cfs_time_seconds(seconds)); + seconds * HZ); } static inline int cfs_time_before_64(u64 t1, u64 t2) diff --git a/drivers/staging/lustre/include/linux/lnet/api.h b/drivers/staging/lustre/include/linux/lnet/api.h index 31fcd33171b4..dae2e4f0056c 100644 --- a/drivers/staging/lustre/include/linux/lnet/api.h +++ b/drivers/staging/lustre/include/linux/lnet/api.h @@ -169,6 +169,7 @@ int LNetEQFree(struct lnet_handle_eq eventq_in); int LNetEQPoll(struct lnet_handle_eq *eventqs_in, int neq_in, int timeout_ms, + int interruptible, struct lnet_event *event_out, int *which_eq_out); /** @} lnet_eq */ diff --git a/drivers/staging/lustre/lnet/Kconfig b/drivers/staging/lustre/lnet/Kconfig index 6bcb53d0c6f4..ad049e6f24e4 100644 --- a/drivers/staging/lustre/lnet/Kconfig +++ b/drivers/staging/lustre/lnet/Kconfig @@ -1,6 +1,6 @@ config LNET tristate "Lustre networking subsystem (LNet)" - depends on INET && m + depends on INET help The Lustre network layer, also known as LNet, is a networking abstaction level API that was initially created to allow Lustre Filesystem to utilize diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index ec84edfda271..7ae2955c4db6 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1211,7 +1211,7 @@ static struct kib_hca_dev *kiblnd_current_hdev(struct kib_dev *dev) CDEBUG(D_NET, "%s: Wait for failover\n", dev->ibd_ifname); set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1) / 100); + schedule_timeout(HZ / 100); read_lock_irqsave(&kiblnd_data.kib_global_lock, flags); } @@ -1921,7 +1921,7 @@ struct list_head *kiblnd_pool_alloc_node(struct kib_poolset *ps) set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(interval); - if (interval < cfs_time_seconds(1)) + if (interval < HZ) interval *= 2; goto again; @@ -2541,7 +2541,7 @@ static void kiblnd_base_shutdown(void) "Waiting for %d threads to terminate\n", atomic_read(&kiblnd_data.kib_nthreads)); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); } /* fall through */ @@ -2592,7 +2592,7 @@ static void kiblnd_shutdown(struct lnet_ni *ni) libcfs_nid2str(ni->ni_nid), atomic_read(&net->ibn_npeers)); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); } kiblnd_net_fini_pools(net); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index b3e7f28eb978..6690a6cd4e34 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -3288,8 +3288,6 @@ kiblnd_connd(void *arg) int peer_index = 0; unsigned long deadline = jiffies; - cfs_block_allsigs(); - init_waitqueue_entry(&wait, current); kiblnd_data.kib_connd = current; @@ -3542,8 +3540,6 @@ kiblnd_scheduler(void *arg) int busy_loops = 0; int rc; - cfs_block_allsigs(); - init_waitqueue_entry(&wait, current); sched = kiblnd_data.kib_scheds[KIB_THREAD_CPT(id)]; @@ -3676,8 +3672,6 @@ kiblnd_failover_thread(void *arg) LASSERT(*kiblnd_tunables.kib_dev_failover); - cfs_block_allsigs(); - init_waitqueue_entry(&wait, current); write_lock_irqsave(glock, flags); @@ -3728,8 +3722,8 @@ kiblnd_failover_thread(void *arg) add_wait_queue(&kiblnd_data.kib_failover_waitq, &wait); write_unlock_irqrestore(glock, flags); - rc = schedule_timeout(long_sleep ? cfs_time_seconds(10) : - cfs_time_seconds(1)); + rc = schedule_timeout(long_sleep ? 10 * HZ : + HZ); remove_wait_queue(&kiblnd_data.kib_failover_waitq, &wait); write_lock_irqsave(glock, flags); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index ff292216290d..7086678e1c3e 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -1677,7 +1677,7 @@ ksocknal_destroy_conn(struct ksock_conn *conn) switch (conn->ksnc_rx_state) { case SOCKNAL_RX_LNET_PAYLOAD: last_rcv = conn->ksnc_rx_deadline - - cfs_time_seconds(*ksocknal_tunables.ksnd_timeout); + *ksocknal_tunables.ksnd_timeout * HZ; CERROR("Completing partial receive from %s[%d], ip %pI4h:%d, with error, wanted: %zd, left: %d, last alive is %ld secs ago\n", libcfs_id2str(conn->ksnc_peer->ksnp_id), conn->ksnc_type, &conn->ksnc_ipaddr, conn->ksnc_port, @@ -2356,7 +2356,7 @@ ksocknal_base_shutdown(void) ksocknal_data.ksnd_nthreads); read_unlock(&ksocknal_data.ksnd_global_lock); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); read_lock(&ksocknal_data.ksnd_global_lock); } read_unlock(&ksocknal_data.ksnd_global_lock); @@ -2599,7 +2599,7 @@ ksocknal_shutdown(struct lnet_ni *ni) "waiting for %d peers to disconnect\n", net->ksnn_npeers); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); ksocknal_debug_peerhash(ni); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h index d50ebdf863fa..570f54ed57b1 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h @@ -304,15 +304,6 @@ struct ksock_tx { /* transmit packet */ /* network zero copy callback descriptor embedded in struct ksock_tx */ -/* - * space for the rx frag descriptors; we either read a single contiguous - * header, or up to LNET_MAX_IOV frags of payload of either type. - */ -union ksock_rxiovspace { - struct kvec iov[LNET_MAX_IOV]; - struct bio_vec kiov[LNET_MAX_IOV]; -}; - #define SOCKNAL_RX_KSM_HEADER 1 /* reading ksock message header */ #define SOCKNAL_RX_LNET_HEADER 2 /* reading lnet message header */ #define SOCKNAL_RX_PARSE 3 /* Calling lnet_parse() */ @@ -359,7 +350,7 @@ struct ksock_conn { __u8 ksnc_rx_state; /* what is being read */ int ksnc_rx_nob_left; /* # bytes to next hdr/body */ struct iov_iter ksnc_rx_to; /* copy destination */ - union ksock_rxiovspace ksnc_rx_iov_space; /* space for frag descriptors */ + struct kvec ksnc_rx_iov_space[LNET_MAX_IOV]; /* space for frag descriptors */ __u32 ksnc_rx_csum; /* partial checksum for incoming * data */ diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c index 11fd3a36424f..036fecbcede8 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c @@ -189,7 +189,7 @@ ksocknal_transmit(struct ksock_conn *conn, struct ksock_tx *tx) if (ksocknal_data.ksnd_stall_tx) { set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_tx)); + schedule_timeout(ksocknal_data.ksnd_stall_tx * HZ); } LASSERT(tx->tx_resid); @@ -294,7 +294,7 @@ ksocknal_receive(struct ksock_conn *conn) if (ksocknal_data.ksnd_stall_rx) { set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(ksocknal_data.ksnd_stall_rx)); + schedule_timeout(ksocknal_data.ksnd_stall_rx * HZ); } rc = ksocknal_connsock_addref(conn); @@ -986,7 +986,7 @@ int ksocknal_new_packet(struct ksock_conn *conn, int nob_to_skip) { static char ksocknal_slop_buffer[4096]; - struct kvec *kvec = (struct kvec *)&conn->ksnc_rx_iov_space; + struct kvec *kvec = conn->ksnc_rx_iov_space; int nob; unsigned int niov; @@ -1059,7 +1059,7 @@ ksocknal_new_packet(struct ksock_conn *conn, int nob_to_skip) static int ksocknal_process_receive(struct ksock_conn *conn) { - struct kvec *kvec = (struct kvec *)&conn->ksnc_rx_iov_space; + struct kvec *kvec = conn->ksnc_rx_iov_space; struct lnet_hdr *lhdr; struct lnet_process_id *id; int rc; @@ -1324,8 +1324,6 @@ int ksocknal_scheduler(void *arg) info = ksocknal_data.ksnd_sched_info[KSOCK_THREAD_CPT(id)]; sched = &info->ksi_scheds[KSOCK_THREAD_SID(id)]; - cfs_block_allsigs(); - rc = cfs_cpt_bind(lnet_cpt_table(), info->ksi_cpt); if (rc) { CWARN("Can't set CPU partition affinity to %d: %d\n", @@ -1780,7 +1778,7 @@ ksocknal_connect(struct ksock_route *route) int rc = 0; deadline = cfs_time_add(cfs_time_current(), - cfs_time_seconds(*ksocknal_tunables.ksnd_timeout)); + *ksocknal_tunables.ksnd_timeout * HZ); write_lock_bh(&ksocknal_data.ksnd_global_lock); @@ -1878,7 +1876,7 @@ ksocknal_connect(struct ksock_route *route) * so min_reconnectms should be good heuristic */ route->ksnr_retry_interval = - cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms) / 1000; + *ksocknal_tunables.ksnd_min_reconnectms * HZ / 1000; route->ksnr_timeout = cfs_time_add(cfs_time_current(), route->ksnr_retry_interval); } @@ -1899,10 +1897,10 @@ ksocknal_connect(struct ksock_route *route) route->ksnr_retry_interval *= 2; route->ksnr_retry_interval = max(route->ksnr_retry_interval, - cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms) / 1000); + (long)*ksocknal_tunables.ksnd_min_reconnectms * HZ / 1000); route->ksnr_retry_interval = min(route->ksnr_retry_interval, - cfs_time_seconds(*ksocknal_tunables.ksnd_max_reconnectms) / 1000); + (long)*ksocknal_tunables.ksnd_max_reconnectms * HZ / 1000); LASSERT(route->ksnr_retry_interval); route->ksnr_timeout = cfs_time_add(cfs_time_current(), @@ -1972,7 +1970,7 @@ ksocknal_connd_check_start(time64_t sec, long *timeout) if (sec - ksocknal_data.ksnd_connd_failed_stamp <= 1) { /* may run out of resource, retry later */ - *timeout = cfs_time_seconds(1); + *timeout = HZ; return 0; } @@ -2031,8 +2029,8 @@ ksocknal_connd_check_stop(time64_t sec, long *timeout) val = (int)(ksocknal_data.ksnd_connd_starting_stamp + SOCKNAL_CONND_TIMEOUT - sec); - *timeout = (val > 0) ? cfs_time_seconds(val) : - cfs_time_seconds(SOCKNAL_CONND_TIMEOUT); + *timeout = (val > 0) ? val * HZ : + SOCKNAL_CONND_TIMEOUT * HZ; if (val > 0) return 0; @@ -2078,8 +2076,6 @@ ksocknal_connd(void *arg) int nloops = 0; int cons_retry = 0; - cfs_block_allsigs(); - init_waitqueue_entry(&wait, current); spin_lock_bh(connd_lock); @@ -2307,7 +2303,7 @@ ksocknal_send_keepalive_locked(struct ksock_peer *peer) if (*ksocknal_tunables.ksnd_keepalive <= 0 || time_before(cfs_time_current(), cfs_time_add(peer->ksnp_last_alive, - cfs_time_seconds(*ksocknal_tunables.ksnd_keepalive)))) + *ksocknal_tunables.ksnd_keepalive * HZ))) return 0; if (time_before(cfs_time_current(), peer->ksnp_send_keepalive)) @@ -2472,8 +2468,6 @@ ksocknal_reaper(void *arg) int peer_index = 0; unsigned long deadline = cfs_time_current(); - cfs_block_allsigs(); - INIT_LIST_HEAD(&enomem_conns); init_waitqueue_entry(&wait, current); @@ -2563,7 +2557,7 @@ ksocknal_reaper(void *arg) ksocknal_data.ksnd_peer_hash_size; } - deadline = cfs_time_add(deadline, cfs_time_seconds(p)); + deadline = cfs_time_add(deadline, p * HZ); } if (nenomem_conns) { diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c index cb28dd2baf2f..7941cfa526bc 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib.c @@ -189,7 +189,7 @@ ksocknal_lib_recv(struct ksock_conn *conn) if (!(conn->ksnc_rx_to.type & ITER_BVEC) && conn->ksnc_proto != &ksocknal_protocol_v2x) return rc; - + /* accumulate checksum */ conn->ksnc_msg.ksm_csum = 0; iov_iter_for_each_range(&conn->ksnc_rx_to, rc, lustre_csum, conn); diff --git a/drivers/staging/lustre/lnet/libcfs/Makefile b/drivers/staging/lustre/lnet/libcfs/Makefile index 730f2c675047..b7dc7ac11cc5 100644 --- a/drivers/staging/lustre/lnet/libcfs/Makefile +++ b/drivers/staging/lustre/lnet/libcfs/Makefile @@ -5,12 +5,10 @@ subdir-ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include obj-$(CONFIG_LNET) += libcfs.o libcfs-linux-objs := linux-tracefile.o linux-debug.o -libcfs-linux-objs += linux-prim.o linux-cpu.o -libcfs-linux-objs += linux-curproc.o +libcfs-linux-objs += linux-cpu.o libcfs-linux-objs += linux-module.o libcfs-linux-objs += linux-crypto.o libcfs-linux-objs += linux-crypto-adler.o -libcfs-linux-objs += linux-mem.o libcfs-linux-objs := $(addprefix linux/,$(libcfs-linux-objs)) diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c index 551c45bf4108..1371224a8cb9 100644 --- a/drivers/staging/lustre/lnet/libcfs/debug.c +++ b/drivers/staging/lustre/lnet/libcfs/debug.c @@ -113,7 +113,7 @@ static int param_set_delay_minmax(const char *val, if (rc) return -EINVAL; - d = cfs_time_seconds(sec) / 100; + d = sec * HZ / 100; if (d < min || d > max) return -EINVAL; @@ -440,7 +440,7 @@ int libcfs_debug_clear_buffer(void) return 0; } -/* Debug markers, although printed by S_LNET should not be be marked as such. */ +/* Debug markers, although printed by S_LNET should not be marked as such. */ #undef DEBUG_SUBSYSTEM #define DEBUG_SUBSYSTEM S_UNDEFINED int libcfs_debug_mark_buffer(const char *text) diff --git a/drivers/staging/lustre/lnet/libcfs/fail.c b/drivers/staging/lustre/lnet/libcfs/fail.c index 39439b303d65..d3f1e866c6a7 100644 --- a/drivers/staging/lustre/lnet/libcfs/fail.c +++ b/drivers/staging/lustre/lnet/libcfs/fail.c @@ -134,7 +134,7 @@ int __cfs_fail_timeout_set(u32 id, u32 value, int ms, int set) CERROR("cfs_fail_timeout id %x sleeping for %dms\n", id, ms); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(ms) / 1000); + schedule_timeout(ms * HZ / 1000); CERROR("cfs_fail_timeout id %x awake\n", id); } return ret; diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c index c07165e0ad95..388521e4e354 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-cpu.c @@ -743,7 +743,7 @@ cfs_cpt_table_create(int ncpt) goto failed; } - if (!zalloc_cpumask_var(&mask, GFP_NOFS)){ + if (!zalloc_cpumask_var(&mask, GFP_NOFS)) { CERROR("Failed to allocate scratch cpumask\n"); goto failed; } diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c index 80072b2a443c..b55006264155 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-crypto.c @@ -42,7 +42,7 @@ static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX]; /** * Initialize the state descriptor for the specified hash algorithm. * - * An internal routine to allocate the hash-specific state in \a hdesc for + * An internal routine to allocate the hash-specific state in \a req for * use with cfs_crypto_hash_digest() to compute the hash of a single message, * though possibly in multiple chunks. The descriptor internal state should * be freed with cfs_crypto_hash_final(). @@ -50,7 +50,7 @@ static int cfs_crypto_hash_speeds[CFS_HASH_ALG_MAX]; * \param[in] hash_alg hash algorithm id (CFS_HASH_ALG_*) * \param[out] type pointer to the hash description in hash_types[] * array - * \param[in,out] hdesc hash state descriptor to be initialized + * \param[in,out] req hash state descriptor to be initialized * \param[in] key initial hash value/state, NULL to use default * value * \param[in] key_len length of \a key @@ -194,7 +194,7 @@ EXPORT_SYMBOL(cfs_crypto_hash_digest); * \retval pointer to descriptor of hash instance * \retval ERR_PTR(errno) in case of error */ -struct cfs_crypto_hash_desc * +struct ahash_request * cfs_crypto_hash_init(enum cfs_crypto_hash_alg hash_alg, unsigned char *key, unsigned int key_len) { @@ -206,14 +206,14 @@ cfs_crypto_hash_init(enum cfs_crypto_hash_alg hash_alg, if (err) return ERR_PTR(err); - return (struct cfs_crypto_hash_desc *)req; + return req; } EXPORT_SYMBOL(cfs_crypto_hash_init); /** * Update hash digest computed on data within the given \a page * - * \param[in] hdesc hash state descriptor + * \param[in] hreq hash state descriptor * \param[in] page data page on which to compute the hash * \param[in] offset offset within \a page at which to start hash * \param[in] len length of data on which to compute hash @@ -221,11 +221,10 @@ EXPORT_SYMBOL(cfs_crypto_hash_init); * \retval 0 for success * \retval negative errno on failure */ -int cfs_crypto_hash_update_page(struct cfs_crypto_hash_desc *hdesc, +int cfs_crypto_hash_update_page(struct ahash_request *req, struct page *page, unsigned int offset, unsigned int len) { - struct ahash_request *req = (void *)hdesc; struct scatterlist sl; sg_init_table(&sl, 1); @@ -239,17 +238,16 @@ EXPORT_SYMBOL(cfs_crypto_hash_update_page); /** * Update hash digest computed on the specified data * - * \param[in] hdesc hash state descriptor + * \param[in] req hash state descriptor * \param[in] buf data buffer on which to compute the hash * \param[in] buf_len length of \buf on which to compute hash * * \retval 0 for success * \retval negative errno on failure */ -int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *hdesc, +int cfs_crypto_hash_update(struct ahash_request *req, const void *buf, unsigned int buf_len) { - struct ahash_request *req = (void *)hdesc; struct scatterlist sl; sg_init_one(&sl, buf, buf_len); @@ -262,20 +260,19 @@ EXPORT_SYMBOL(cfs_crypto_hash_update); /** * Finish hash calculation, copy hash digest to buffer, clean up hash descriptor * - * \param[in] hdesc hash descriptor + * \param[in] req hash descriptor * \param[out] hash pointer to hash buffer to store hash digest - * \param[in,out] hash_len pointer to hash buffer size, if \a hdesc = NULL - * only free \a hdesc instead of computing the hash + * \param[in,out] hash_len pointer to hash buffer size, if \a req = NULL + * only free \a req instead of computing the hash * * \retval 0 for success * \retval -EOVERFLOW if hash_len is too small for the hash digest * \retval negative errno for other errors from lower layers */ -int cfs_crypto_hash_final(struct cfs_crypto_hash_desc *hdesc, +int cfs_crypto_hash_final(struct ahash_request *req, unsigned char *hash, unsigned int *hash_len) { int err; - struct ahash_request *req = (void *)hdesc; int size = crypto_ahash_digestsize(crypto_ahash_reqtfm(req)); if (!hash || !hash_len) { @@ -331,7 +328,7 @@ static void cfs_crypto_performance_test(enum cfs_crypto_hash_alg hash_alg) for (start = jiffies, end = start + msecs_to_jiffies(MSEC_PER_SEC), bcount = 0; time_before(jiffies, end); bcount++) { - struct cfs_crypto_hash_desc *hdesc; + struct ahash_request *hdesc; int i; hdesc = cfs_crypto_hash_init(hash_alg, NULL, 0); diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c deleted file mode 100644 index 1d8949f1a4fa..000000000000 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-curproc.c +++ /dev/null @@ -1,108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2015, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - * - * libcfs/libcfs/linux/linux-curproc.c - * - * Lustre curproc API implementation for Linux kernel - * - * Author: Nikita Danilov <nikita@clusterfs.com> - */ - -#include <linux/sched.h> -#include <linux/fs_struct.h> - -#include <linux/compat.h> -#include <linux/thread_info.h> - -#define DEBUG_SUBSYSTEM S_LNET - -#include <linux/libcfs/libcfs.h> - -/* - * Implementation of cfs_curproc API (see portals/include/libcfs/curproc.h) - * for Linux kernel. - */ - -void cfs_cap_raise(cfs_cap_t cap) -{ - struct cred *cred; - - cred = prepare_creds(); - if (cred) { - cap_raise(cred->cap_effective, cap); - commit_creds(cred); - } -} -EXPORT_SYMBOL(cfs_cap_raise); - -void cfs_cap_lower(cfs_cap_t cap) -{ - struct cred *cred; - - cred = prepare_creds(); - if (cred) { - cap_lower(cred->cap_effective, cap); - commit_creds(cred); - } -} -EXPORT_SYMBOL(cfs_cap_lower); - -int cfs_cap_raised(cfs_cap_t cap) -{ - return cap_raised(current_cap(), cap); -} -EXPORT_SYMBOL(cfs_cap_raised); - -static void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap) -{ - /* XXX lost high byte */ - *cap = kcap.cap[0]; -} - -cfs_cap_t cfs_curproc_cap_pack(void) -{ - cfs_cap_t cap; - - cfs_kernel_cap_pack(current_cap(), &cap); - return cap; -} -EXPORT_SYMBOL(cfs_curproc_cap_pack); - -/* - * Local variables: - * c-indentation-style: "K&R" - * c-basic-offset: 8 - * tab-width: 8 - * fill-column: 80 - * scroll-step: 1 - * End: - */ diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c deleted file mode 100644 index 963df0ef4afb..000000000000 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-mem.c +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - */ -/* - * This file creates a memory allocation primitive for Lustre, that - * allows to fallback to vmalloc allocations should regular kernel allocations - * fail due to size or system memory fragmentation. - * - * Author: Oleg Drokin <green@linuxhacker.ru> - * - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Seagate Technology. - */ -#include <linux/slab.h> -#include <linux/vmalloc.h> - -#include <linux/libcfs/libcfs.h> - -void *libcfs_kvzalloc(size_t size, gfp_t flags) -{ - void *ret; - - ret = kzalloc(size, flags | __GFP_NOWARN); - if (!ret) - ret = __vmalloc(size, flags | __GFP_ZERO, PAGE_KERNEL); - return ret; -} -EXPORT_SYMBOL(libcfs_kvzalloc); - -void *libcfs_kvzalloc_cpt(struct cfs_cpt_table *cptab, int cpt, size_t size, - gfp_t flags) -{ - return kvzalloc_node(size, flags, cfs_cpt_spread_node(cptab, cpt)); -} -EXPORT_SYMBOL(libcfs_kvzalloc_cpt); diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c deleted file mode 100644 index 6f92ea272186..000000000000 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-prim.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * 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 version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. - * Use is subject to license terms. - * - * Copyright (c) 2011, 2012, Intel Corporation. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. - */ - -#define DEBUG_SUBSYSTEM S_LNET -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/fs_struct.h> -#include <linux/sched/signal.h> - -#include <linux/libcfs/libcfs.h> - -#if defined(CONFIG_KGDB) -#include <linux/kgdb.h> -#endif - -sigset_t -cfs_block_allsigs(void) -{ - unsigned long flags; - sigset_t old; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - old = current->blocked; - sigfillset(¤t->blocked); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - - return old; -} -EXPORT_SYMBOL(cfs_block_allsigs); - -sigset_t cfs_block_sigs(unsigned long sigs) -{ - unsigned long flags; - sigset_t old; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - old = current->blocked; - sigaddsetmask(¤t->blocked, sigs); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - return old; -} -EXPORT_SYMBOL(cfs_block_sigs); - -/* Block all signals except for the @sigs */ -sigset_t cfs_block_sigsinv(unsigned long sigs) -{ - unsigned long flags; - sigset_t old; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - old = current->blocked; - sigaddsetmask(¤t->blocked, ~sigs); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - - return old; -} -EXPORT_SYMBOL(cfs_block_sigsinv); - -void -cfs_restore_sigs(sigset_t old) -{ - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - current->blocked = old; - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); -} -EXPORT_SYMBOL(cfs_restore_sigs); - -void -cfs_clear_sigpending(void) -{ - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - clear_tsk_thread_flag(current, TIF_SIGPENDING); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); -} -EXPORT_SYMBOL(cfs_clear_sigpending); diff --git a/drivers/staging/lustre/lnet/libcfs/tracefile.c b/drivers/staging/lustre/lnet/libcfs/tracefile.c index 57913aae1d88..4affca750bc5 100644 --- a/drivers/staging/lustre/lnet/libcfs/tracefile.c +++ b/drivers/staging/lustre/lnet/libcfs/tracefile.c @@ -441,7 +441,7 @@ console: if (cfs_time_after(cfs_time_current(), cdls->cdls_next + libcfs_console_max_delay + - cfs_time_seconds(10))) { + 10 * HZ)) { /* last timeout was a long time ago */ cdls->cdls_delay /= libcfs_console_backoff * 4; } else { @@ -1071,7 +1071,7 @@ end_loop: init_waitqueue_entry(&__wait, current); add_wait_queue(&tctl->tctl_waitq, &__wait); set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); remove_wait_queue(&tctl->tctl_waitq, &__wait); } complete(&tctl->tctl_stop); diff --git a/drivers/staging/lustre/lnet/lnet/acceptor.c b/drivers/staging/lustre/lnet/lnet/acceptor.c index ee85cab6f437..5648f17eddc0 100644 --- a/drivers/staging/lustre/lnet/lnet/acceptor.c +++ b/drivers/staging/lustre/lnet/lnet/acceptor.c @@ -240,7 +240,7 @@ lnet_accept(struct socket *sock, __u32 magic) return -EPROTO; } - if (magic == le32_to_cpu(LNET_PROTO_TCP_MAGIC)) + if (lnet_accept_magic(magic, LNET_PROTO_TCP_MAGIC)) str = "'old' socknal/tcpnal"; else str = "unrecognised"; @@ -335,8 +335,6 @@ lnet_acceptor(void *arg) LASSERT(!lnet_acceptor_state.pta_sock); - cfs_block_allsigs(); - rc = lnet_sock_listen(&lnet_acceptor_state.pta_sock, 0, accept_port, accept_backlog); if (rc) { @@ -365,7 +363,7 @@ lnet_acceptor(void *arg) if (rc != -EAGAIN) { CWARN("Accept error %d: pausing...\n", rc); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); } continue; } diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 2c7abad57104..90266be0132d 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -961,19 +961,15 @@ static void lnet_ping_md_unlink(struct lnet_ping_info *pinfo, struct lnet_handle_md *md_handle) { - sigset_t blocked = cfs_block_allsigs(); - LNetMDUnlink(*md_handle); LNetInvalidateMDHandle(md_handle); /* NB md could be busy; this just starts the unlink */ while (pinfo->pi_features != LNET_PING_FEAT_INVAL) { CDEBUG(D_NET, "Still waiting for ping MD to unlink\n"); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + set_current_state(TASK_NOLOAD); + schedule_timeout(HZ); } - - cfs_restore_sigs(blocked); } static void @@ -1109,7 +1105,7 @@ lnet_clear_zombies_nis_locked(void) libcfs_nid2str(ni->ni_nid)); } set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); lnet_net_lock(LNET_LOCK_EX); continue; } @@ -1218,6 +1214,7 @@ lnet_startup_lndni(struct lnet_ni *ni, struct lnet_ioctl_config_data *conf) struct lnet_lnd *lnd; struct lnet_tx_queue *tq; int i; + u32 seed; lnd_type = LNET_NETTYP(LNET_NIDNET(ni->ni_nid)); @@ -1356,6 +1353,12 @@ lnet_startup_lndni(struct lnet_ni *ni, struct lnet_ioctl_config_data *conf) tq->tq_credits = lnet_ni_tq_credits(ni); } + /* Nodes with small feet have little entropy. The NID for this + * node gives the most entropy in the low bits. + */ + seed = LNET_NIDADDR(ni->ni_nid); + add_device_randomness(&seed, sizeof(seed)); + CDEBUG(D_LNI, "Added LNI %s [%d/%d/%d/%d]\n", libcfs_nid2str(ni->ni_nid), ni->ni_peertxcredits, lnet_ni_tq_credits(ni) * LNET_CPT_NUMBER, @@ -2141,7 +2144,6 @@ static int lnet_ping(struct lnet_process_id id, int timeout_ms, int nob; int rc; int rc2; - sigset_t blocked; infosz = offsetof(struct lnet_ping_info, pi_ni[n_ids]); @@ -2197,13 +2199,9 @@ static int lnet_ping(struct lnet_process_id id, int timeout_ms, do { /* MUST block for unlink to complete */ - if (unlinked) - blocked = cfs_block_allsigs(); - - rc2 = LNetEQPoll(&eqh, 1, timeout_ms, &event, &which); - if (unlinked) - cfs_restore_sigs(blocked); + rc2 = LNetEQPoll(&eqh, 1, timeout_ms, !unlinked, + &event, &which); CDEBUG(D_NET, "poll %d(%d %d)%s\n", rc2, (rc2 <= 0) ? -1 : event.type, diff --git a/drivers/staging/lustre/lnet/lnet/lib-eq.c b/drivers/staging/lustre/lnet/lnet/lib-eq.c index a173b69e2f92..ea53b5cb3f72 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-eq.c +++ b/drivers/staging/lustre/lnet/lnet/lib-eq.c @@ -308,7 +308,7 @@ lnet_eq_dequeue_event(struct lnet_eq *eq, struct lnet_event *ev) */ static int -lnet_eq_wait_locked(int *timeout_ms) +lnet_eq_wait_locked(int *timeout_ms, long state) __must_hold(&the_lnet.ln_eq_wait_lock) { int tms = *timeout_ms; @@ -320,7 +320,7 @@ __must_hold(&the_lnet.ln_eq_wait_lock) return -ENXIO; /* don't want to wait and no new event */ init_waitqueue_entry(&wl, current); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(state); add_wait_queue(&the_lnet.ln_eq_waitq, &wl); lnet_eq_wait_unlock(); @@ -359,6 +359,7 @@ __must_hold(&the_lnet.ln_eq_wait_lock) * \param timeout_ms Time in milliseconds to wait for an event to occur on * one of the EQs. The constant LNET_TIME_FOREVER can be used to indicate an * infinite timeout. + * \param interruptible, if true, use TASK_INTERRUPTIBLE, else TASK_NOLOAD * \param event,which On successful return (1 or -EOVERFLOW), \a event will * hold the next event in the EQs, and \a which will contain the index of the * EQ from which the event was taken. @@ -372,6 +373,7 @@ __must_hold(&the_lnet.ln_eq_wait_lock) */ int LNetEQPoll(struct lnet_handle_eq *eventqs, int neq, int timeout_ms, + int interruptible, struct lnet_event *event, int *which) { int wait = 1; @@ -412,7 +414,9 @@ LNetEQPoll(struct lnet_handle_eq *eventqs, int neq, int timeout_ms, * 0 : don't want to wait anymore, but might have new event * so need to call dequeue again */ - wait = lnet_eq_wait_locked(&timeout_ms); + wait = lnet_eq_wait_locked(&timeout_ms, + interruptible ? TASK_INTERRUPTIBLE + : TASK_NOLOAD); if (wait < 0) /* no new event */ break; } diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index c673037dbce4..ed43b3f4b114 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -524,7 +524,7 @@ lnet_peer_is_alive(struct lnet_peer *lp, unsigned long now) return 0; deadline = cfs_time_add(lp->lp_last_alive, - cfs_time_seconds(lp->lp_ni->ni_peertimeout)); + lp->lp_ni->ni_peertimeout * HZ); alive = cfs_time_after(deadline, now); /* Update obsolete lp_alive except for routers assumed to be dead @@ -562,7 +562,7 @@ lnet_peer_alive_locked(struct lnet_peer *lp) unsigned long next_query = cfs_time_add(lp->lp_last_query, - cfs_time_seconds(lnet_queryinterval)); + lnet_queryinterval * HZ); if (time_before(now, next_query)) { if (lp->lp_alive) diff --git a/drivers/staging/lustre/lnet/lnet/lib-ptl.c b/drivers/staging/lustre/lnet/lnet/lib-ptl.c index 471f2f6c86f4..fc47379c5938 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-ptl.c +++ b/drivers/staging/lustre/lnet/lnet/lib-ptl.c @@ -841,6 +841,7 @@ lnet_portals_destroy(void) cfs_array_free(the_lnet.ln_portals); the_lnet.ln_portals = NULL; + the_lnet.ln_nportals = 0; } int @@ -851,12 +852,12 @@ lnet_portals_create(void) size = offsetof(struct lnet_portal, ptl_mt_maps[LNET_CPT_NUMBER]); - the_lnet.ln_nportals = MAX_PORTALS; - the_lnet.ln_portals = cfs_array_alloc(the_lnet.ln_nportals, size); + the_lnet.ln_portals = cfs_array_alloc(MAX_PORTALS, size); if (!the_lnet.ln_portals) { CERROR("Failed to allocate portals table\n"); return -ENOMEM; } + the_lnet.ln_nportals = MAX_PORTALS; for (i = 0; i < the_lnet.ln_nportals; i++) { if (lnet_ptl_setup(the_lnet.ln_portals[i], i)) { diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c index e3468cef273b..a63b7941d435 100644 --- a/drivers/staging/lustre/lnet/lnet/net_fault.c +++ b/drivers/staging/lustre/lnet/lnet/net_fault.c @@ -315,9 +315,8 @@ drop_rule_match(struct lnet_drop_rule *rule, lnet_nid_t src, rule->dr_time_base = now; rule->dr_drop_time = rule->dr_time_base + - cfs_time_seconds( - prandom_u32_max(attr->u.drop.da_interval)); - rule->dr_time_base += cfs_time_seconds(attr->u.drop.da_interval); + prandom_u32_max(attr->u.drop.da_interval) * HZ; + rule->dr_time_base += attr->u.drop.da_interval * HZ; CDEBUG(D_NET, "Drop Rule %s->%s: next drop : %lu\n", libcfs_nid2str(attr->fa_src), @@ -440,8 +439,7 @@ static struct delay_daemon_data delay_dd; static unsigned long round_timeout(unsigned long timeout) { - return cfs_time_seconds((unsigned int) - cfs_duration_sec(cfs_time_sub(timeout, 0)) + 1); + return (unsigned int)rounddown(timeout, HZ) + HZ; } static void @@ -483,10 +481,8 @@ delay_rule_match(struct lnet_delay_rule *rule, lnet_nid_t src, rule->dl_time_base = now; rule->dl_delay_time = rule->dl_time_base + - cfs_time_seconds( - prandom_u32_max( - attr->u.delay.la_interval)); - rule->dl_time_base += cfs_time_seconds(attr->u.delay.la_interval); + prandom_u32_max(attr->u.delay.la_interval) * HZ; + rule->dl_time_base += attr->u.delay.la_interval * HZ; CDEBUG(D_NET, "Delay Rule %s->%s: next delay : %lu\n", libcfs_nid2str(attr->fa_src), diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 3e157c10fec4..3d4caa609c83 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -137,7 +137,7 @@ lnet_peer_table_deathrow_wait_locked(struct lnet_peer_table *ptable, ptable->pt_zombies); } set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1) >> 1); + schedule_timeout(HZ >> 1); lnet_net_lock(cpt_locked); } } diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c index 6504761ca598..a3c3f4959f46 100644 --- a/drivers/staging/lustre/lnet/lnet/router.c +++ b/drivers/staging/lustre/lnet/lnet/router.c @@ -808,7 +808,7 @@ lnet_wait_known_routerstate(void) return; set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); } } @@ -1011,7 +1011,7 @@ lnet_ping_router_locked(struct lnet_peer *rtr) if (secs && !rtr->lp_ping_notsent && cfs_time_after(now, cfs_time_add(rtr->lp_ping_timestamp, - cfs_time_seconds(secs)))) { + secs * HZ))) { int rc; struct lnet_process_id id; struct lnet_handle_md mdh; @@ -1185,7 +1185,7 @@ lnet_prune_rc_data(int wait_unlink) CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET, "Waiting for rc buffers to unlink\n"); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1) / 4); + schedule_timeout(HZ / 4); lnet_net_lock(LNET_LOCK_EX); } @@ -1226,8 +1226,6 @@ lnet_router_checker(void *arg) struct lnet_peer *rtr; struct list_head *entry; - cfs_block_allsigs(); - while (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING) { __u64 version; int cpt; @@ -1282,7 +1280,7 @@ rescan: else wait_event_interruptible_timeout(the_lnet.ln_rc_waitq, false, - cfs_time_seconds(1)); + HZ); } lnet_prune_rc_data(1); /* wait for UNLINK */ diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c index 34ba440b3c02..a2d8092bdeb7 100644 --- a/drivers/staging/lustre/lnet/selftest/conctl.c +++ b/drivers/staging/lustre/lnet/selftest/conctl.c @@ -648,14 +648,10 @@ static int lst_test_add_ioctl(struct lstio_test_args *args) return -EINVAL; if (args->lstio_tes_param) { - param = kmalloc(args->lstio_tes_param_len, GFP_KERNEL); - if (!param) - goto out; - if (copy_from_user(param, args->lstio_tes_param, - args->lstio_tes_param_len)) { - rc = -EFAULT; - goto out; - } + param = memdup_user(args->lstio_tes_param, + args->lstio_tes_param_len); + if (IS_ERR(param)) + return PTR_ERR(param); } rc = -EFAULT; @@ -674,7 +670,7 @@ static int lst_test_add_ioctl(struct lstio_test_args *args) args->lstio_tes_param_len, &ret, args->lstio_tes_resultp); - if (ret) + if (!rc && ret) rc = (copy_to_user(args->lstio_tes_retp, &ret, sizeof(ret))) ? -EFAULT : 0; out: diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c index 7aa515c34594..6dcc966b293b 100644 --- a/drivers/staging/lustre/lnet/selftest/conrpc.c +++ b/drivers/staging/lustre/lnet/selftest/conrpc.c @@ -359,7 +359,7 @@ lstcon_rpc_trans_postwait(struct lstcon_rpc_trans *trans, int timeout) rc = wait_event_interruptible_timeout(trans->tas_waitq, lstcon_rpc_trans_check(trans), - cfs_time_seconds(timeout)); + timeout * HZ); rc = (rc > 0) ? 0 : ((rc < 0) ? -EINTR : -ETIMEDOUT); mutex_lock(&console_session.ses_mutex); @@ -1350,7 +1350,7 @@ lstcon_rpc_cleanup_wait(void) CWARN("Session is shutting down, waiting for termination of transactions\n"); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); mutex_lock(&console_session.ses_mutex); } diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c index c7697f66f663..0ca1e3a780ca 100644 --- a/drivers/staging/lustre/lnet/selftest/framework.c +++ b/drivers/staging/lustre/lnet/selftest/framework.c @@ -187,7 +187,7 @@ sfw_del_session_timer(void) return 0; } - return EBUSY; /* racing with sfw_session_expired() */ + return -EBUSY; /* racing with sfw_session_expired() */ } static void diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c index f8198ad1046e..9613b0a77007 100644 --- a/drivers/staging/lustre/lnet/selftest/rpc.c +++ b/drivers/staging/lustre/lnet/selftest/rpc.c @@ -1604,7 +1604,7 @@ srpc_startup(void) /* 1 second pause to avoid timestamp reuse */ set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); srpc_data.rpc_matchbits = ((__u64)ktime_get_real_seconds()) << 48; srpc_data.rpc_state = SRPC_STATE_NONE; diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h index ad04534f000c..05466b85e1c0 100644 --- a/drivers/staging/lustre/lnet/selftest/selftest.h +++ b/drivers/staging/lustre/lnet/selftest/selftest.h @@ -575,7 +575,7 @@ swi_state2str(int state) #define selftest_wait_events() \ do { \ set_current_state(TASK_UNINTERRUPTIBLE); \ - schedule_timeout(cfs_time_seconds(1) / 10); \ + schedule_timeout(HZ / 10); \ } while (0) #define lst_wait_until(cond, lock, fmt, ...) \ diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c index ab125a8524c5..1b2c5fc81358 100644 --- a/drivers/staging/lustre/lnet/selftest/timer.c +++ b/drivers/staging/lustre/lnet/selftest/timer.c @@ -170,14 +170,12 @@ stt_timer_main(void *arg) { int rc = 0; - cfs_block_allsigs(); - while (!stt_data.stt_shuttingdown) { stt_check_timers(&stt_data.stt_prev_slot); rc = wait_event_timeout(stt_data.stt_waitq, stt_data.stt_shuttingdown, - cfs_time_seconds(STTIMER_SLOTTIME)); + STTIMER_SLOTTIME * HZ); } spin_lock(&stt_data.stt_lock); diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig index 90d826946c6a..ccb78a945995 100644 --- a/drivers/staging/lustre/lustre/Kconfig +++ b/drivers/staging/lustre/lustre/Kconfig @@ -1,6 +1,5 @@ config LUSTRE_FS tristate "Lustre file system client support" - depends on m && !MIPS && !XTENSA && !SUPERH depends on LNET select CRYPTO select CRYPTO_CRC32 diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c index 009c2367f74e..030680f37c79 100644 --- a/drivers/staging/lustre/lustre/fid/fid_request.c +++ b/drivers/staging/lustre/lustre/fid/fid_request.c @@ -118,22 +118,22 @@ static int seq_client_rpc(struct lu_client_seq *seq, goto out_req; out = req_capsule_server_get(&req->rq_pill, &RMF_SEQ_RANGE); - *output = *out; - if (!lu_seq_range_is_sane(output)) { + if (!lu_seq_range_is_sane(out)) { CERROR("%s: Invalid range received from server: " - DRANGE "\n", seq->lcs_name, PRANGE(output)); + DRANGE "\n", seq->lcs_name, PRANGE(out)); rc = -EINVAL; goto out_req; } - if (lu_seq_range_is_exhausted(output)) { + if (lu_seq_range_is_exhausted(out)) { CERROR("%s: Range received from server is exhausted: " - DRANGE "]\n", seq->lcs_name, PRANGE(output)); + DRANGE "]\n", seq->lcs_name, PRANGE(out)); rc = -EINVAL; goto out_req; } + *output = *out; CDEBUG_LIMIT(debug_mask, "%s: Allocated %s-sequence " DRANGE "]\n", seq->lcs_name, opcname, PRANGE(output)); @@ -174,6 +174,7 @@ static int seq_client_alloc_seq(const struct lu_env *env, if (rc) { CERROR("%s: Can't allocate new meta-sequence, rc %d\n", seq->lcs_name, rc); + *seqnr = U64_MAX; return rc; } CDEBUG(D_INFO, "%s: New range - " DRANGE "\n", @@ -192,71 +193,49 @@ static int seq_client_alloc_seq(const struct lu_env *env, return rc; } -static int seq_fid_alloc_prep(struct lu_client_seq *seq, - wait_queue_entry_t *link) -{ - if (seq->lcs_update) { - add_wait_queue(&seq->lcs_waitq, link); - set_current_state(TASK_UNINTERRUPTIBLE); - mutex_unlock(&seq->lcs_mutex); - - schedule(); - - mutex_lock(&seq->lcs_mutex); - remove_wait_queue(&seq->lcs_waitq, link); - set_current_state(TASK_RUNNING); - return -EAGAIN; - } - ++seq->lcs_update; - mutex_unlock(&seq->lcs_mutex); - return 0; -} - -static void seq_fid_alloc_fini(struct lu_client_seq *seq) -{ - LASSERT(seq->lcs_update == 1); - mutex_lock(&seq->lcs_mutex); - --seq->lcs_update; - wake_up(&seq->lcs_waitq); -} - /* Allocate new fid on passed client @seq and save it to @fid. */ int seq_client_alloc_fid(const struct lu_env *env, struct lu_client_seq *seq, struct lu_fid *fid) { - wait_queue_entry_t link; int rc; LASSERT(seq); LASSERT(fid); - init_waitqueue_entry(&link, current); - mutex_lock(&seq->lcs_mutex); + spin_lock(&seq->lcs_lock); if (OBD_FAIL_CHECK(OBD_FAIL_SEQ_EXHAUST)) seq->lcs_fid.f_oid = seq->lcs_width; - while (1) { + wait_event_cmd(seq->lcs_waitq, + (!fid_is_zero(&seq->lcs_fid) && + fid_oid(&seq->lcs_fid) < seq->lcs_width) || + !seq->lcs_update, + spin_unlock(&seq->lcs_lock), + spin_lock(&seq->lcs_lock)); + + if (!fid_is_zero(&seq->lcs_fid) && + fid_oid(&seq->lcs_fid) < seq->lcs_width) { + /* Just bump last allocated fid and return to caller. */ + seq->lcs_fid.f_oid += 1; + rc = 0; + } else { u64 seqnr; - if (!fid_is_zero(&seq->lcs_fid) && - fid_oid(&seq->lcs_fid) < seq->lcs_width) { - /* Just bump last allocated fid and return to caller. */ - seq->lcs_fid.f_oid += 1; - rc = 0; - break; - } - - rc = seq_fid_alloc_prep(seq, &link); - if (rc) - continue; + LASSERT(seq->lcs_update == 0); + seq->lcs_update = 1; + spin_unlock(&seq->lcs_lock); rc = seq_client_alloc_seq(env, seq, &seqnr); + + spin_lock(&seq->lcs_lock); + seq->lcs_update = 0; + wake_up(&seq->lcs_waitq); + if (rc) { CERROR("%s: Can't allocate new sequence, rc %d\n", seq->lcs_name, rc); - seq_fid_alloc_fini(seq); - mutex_unlock(&seq->lcs_mutex); + spin_unlock(&seq->lcs_lock); return rc; } @@ -272,13 +251,10 @@ int seq_client_alloc_fid(const struct lu_env *env, * to setup FLD for it. */ rc = 1; - - seq_fid_alloc_fini(seq); - break; } *fid = seq->lcs_fid; - mutex_unlock(&seq->lcs_mutex); + spin_unlock(&seq->lcs_lock); CDEBUG(D_INFO, "%s: Allocated FID " DFID "\n", seq->lcs_name, PFID(fid)); @@ -292,23 +268,14 @@ EXPORT_SYMBOL(seq_client_alloc_fid); */ void seq_client_flush(struct lu_client_seq *seq) { - wait_queue_entry_t link; LASSERT(seq); - init_waitqueue_entry(&link, current); - mutex_lock(&seq->lcs_mutex); - - while (seq->lcs_update) { - add_wait_queue(&seq->lcs_waitq, &link); - set_current_state(TASK_UNINTERRUPTIBLE); - mutex_unlock(&seq->lcs_mutex); + spin_lock(&seq->lcs_lock); - schedule(); - - mutex_lock(&seq->lcs_mutex); - remove_wait_queue(&seq->lcs_waitq, &link); - set_current_state(TASK_RUNNING); - } + wait_event_cmd(seq->lcs_waitq, + !seq->lcs_update, + spin_unlock(&seq->lcs_lock), + spin_lock(&seq->lcs_lock)); fid_zero(&seq->lcs_fid); /** @@ -319,7 +286,7 @@ void seq_client_flush(struct lu_client_seq *seq) seq->lcs_space.lsr_index = -1; lu_seq_range_init(&seq->lcs_space); - mutex_unlock(&seq->lcs_mutex); + spin_unlock(&seq->lcs_lock); } EXPORT_SYMBOL(seq_client_flush); @@ -382,7 +349,7 @@ static int seq_client_init(struct lu_client_seq *seq, seq->lcs_type = type; - mutex_init(&seq->lcs_mutex); + spin_lock_init(&seq->lcs_lock); if (type == LUSTRE_SEQ_METADATA) seq->lcs_width = LUSTRE_METADATA_SEQ_MAX_WIDTH; else diff --git a/drivers/staging/lustre/lustre/fid/lproc_fid.c b/drivers/staging/lustre/lustre/fid/lproc_fid.c index 083419f77697..a1e5bf9f36ec 100644 --- a/drivers/staging/lustre/lustre/fid/lproc_fid.c +++ b/drivers/staging/lustre/lustre/fid/lproc_fid.c @@ -98,33 +98,43 @@ ldebugfs_fid_space_seq_write(struct file *file, size_t count, loff_t *off) { struct lu_client_seq *seq; + struct lu_seq_range range; int rc; seq = ((struct seq_file *)file->private_data)->private; - mutex_lock(&seq->lcs_mutex); - rc = ldebugfs_fid_write_common(buffer, count, &seq->lcs_space); + rc = ldebugfs_fid_write_common(buffer, count, &range); - if (rc == 0) { + spin_lock(&seq->lcs_lock); + if (seq->lcs_update) + /* An RPC call is active to update lcs_space */ + rc = -EBUSY; + if (rc > 0) + seq->lcs_space = range; + spin_unlock(&seq->lcs_lock); + + if (rc > 0) { CDEBUG(D_INFO, "%s: Space: " DRANGE "\n", - seq->lcs_name, PRANGE(&seq->lcs_space)); + seq->lcs_name, PRANGE(&range)); } - mutex_unlock(&seq->lcs_mutex); - - return count; + return rc; } static int ldebugfs_fid_space_seq_show(struct seq_file *m, void *unused) { struct lu_client_seq *seq = (struct lu_client_seq *)m->private; + int rc = 0; - mutex_lock(&seq->lcs_mutex); - seq_printf(m, "[%#llx - %#llx]:%x:%s\n", PRANGE(&seq->lcs_space)); - mutex_unlock(&seq->lcs_mutex); + spin_lock(&seq->lcs_lock); + if (seq->lcs_update) + rc = -EBUSY; + else + seq_printf(m, "[%#llx - %#llx]:%x:%s\n", PRANGE(&seq->lcs_space)); + spin_unlock(&seq->lcs_lock); - return 0; + return rc; } static ssize_t @@ -142,7 +152,7 @@ ldebugfs_fid_width_seq_write(struct file *file, if (rc) return rc; - mutex_lock(&seq->lcs_mutex); + spin_lock(&seq->lcs_lock); if (seq->lcs_type == LUSTRE_SEQ_DATA) max = LUSTRE_DATA_SEQ_MAX_WIDTH; else @@ -155,7 +165,7 @@ ldebugfs_fid_width_seq_write(struct file *file, seq->lcs_width); } - mutex_unlock(&seq->lcs_mutex); + spin_unlock(&seq->lcs_lock); return count; } @@ -165,9 +175,9 @@ ldebugfs_fid_width_seq_show(struct seq_file *m, void *unused) { struct lu_client_seq *seq = (struct lu_client_seq *)m->private; - mutex_lock(&seq->lcs_mutex); + spin_lock(&seq->lcs_lock); seq_printf(m, "%llu\n", seq->lcs_width); - mutex_unlock(&seq->lcs_mutex); + spin_unlock(&seq->lcs_lock); return 0; } @@ -177,9 +187,9 @@ ldebugfs_fid_fid_seq_show(struct seq_file *m, void *unused) { struct lu_client_seq *seq = (struct lu_client_seq *)m->private; - mutex_lock(&seq->lcs_mutex); + spin_lock(&seq->lcs_lock); seq_printf(m, DFID "\n", PFID(&seq->lcs_fid)); - mutex_unlock(&seq->lcs_mutex); + spin_unlock(&seq->lcs_lock); return 0; } diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c index ecf8b9e1ed5c..2d61ca4e51cf 100644 --- a/drivers/staging/lustre/lustre/fld/fld_cache.c +++ b/drivers/staging/lustre/lustre/fld/fld_cache.c @@ -263,7 +263,7 @@ static void fld_cache_punch_hole(struct fld_cache *cache, fldt = kzalloc(sizeof(*fldt), GFP_ATOMIC); if (!fldt) { kfree(f_new); - /* overlap is not allowed, so dont mess up list. */ + /* overlap is not allowed, so don't mess up list. */ return; } /* break f_curr RANGE into three RANGES: diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index 90419dca2e1e..341a145c3331 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -1833,7 +1833,7 @@ struct cl_io { */ ci_verify_layout:1, /** - * file is released, restore has to to be triggered by vvp layer + * file is released, restore has to be triggered by vvp layer */ ci_restore_needed:1, /** diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h index 835a729dd8d0..426e8f3c9809 100644 --- a/drivers/staging/lustre/lustre/include/lprocfs_status.h +++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h @@ -114,7 +114,7 @@ struct rename_stats { * LPROCFS_CNTR_AVGMINMAX indicates a multi-valued counter samples, * (i.e. counter can be incremented by more than "1"). When specified, * the counter maintains min, max and sum in addition to a simple - * invocation count. This allows averages to be be computed. + * invocation count. This allows averages to be computed. * If not specified, the counter is an increment-by-1 counter. * min, max, sum, etc. are not maintained. * diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h index 34e35fbff978..35c7b582f36d 100644 --- a/drivers/staging/lustre/lustre/include/lu_object.h +++ b/drivers/staging/lustre/lustre/include/lu_object.h @@ -1328,13 +1328,6 @@ struct lu_kmem_descr { int lu_kmem_init(struct lu_kmem_descr *caches); void lu_kmem_fini(struct lu_kmem_descr *caches); -void lu_buf_free(struct lu_buf *buf); -void lu_buf_alloc(struct lu_buf *buf, size_t size); -void lu_buf_realloc(struct lu_buf *buf, size_t size); - -int lu_buf_check_and_grow(struct lu_buf *buf, size_t len); -struct lu_buf *lu_buf_check_and_alloc(struct lu_buf *buf, size_t len); - extern __u32 lu_context_tags_default; extern __u32 lu_session_tags_default; diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm.h b/drivers/staging/lustre/lustre/include/lustre_dlm.h index e0b17052b2ea..239aa2b1268f 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm.h @@ -60,7 +60,7 @@ struct obd_device; #define OBD_LDLM_DEVICENAME "ldlm" #define LDLM_DEFAULT_LRU_SIZE (100 * num_online_cpus()) -#define LDLM_DEFAULT_MAX_ALIVE (cfs_time_seconds(3900)) /* 65 min */ +#define LDLM_DEFAULT_MAX_ALIVE (65 * 60 * HZ) /* 65 min */ #define LDLM_DEFAULT_PARALLEL_AST_LIMIT 1024 /** diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h index 66ac9dc7302a..40cd168ed2ea 100644 --- a/drivers/staging/lustre/lustre/include/lustre_export.h +++ b/drivers/staging/lustre/lustre/include/lustre_export.h @@ -87,6 +87,8 @@ struct obd_export { struct obd_uuid exp_client_uuid; /** To link all exports on an obd device */ struct list_head exp_obd_chain; + /** work_struct for destruction of export */ + struct work_struct exp_zombie_work; struct hlist_node exp_uuid_hash; /** uuid-export hash*/ /** Obd device of this export */ struct obd_device *exp_obd; diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h index d19c7a27ee48..094ad282de2c 100644 --- a/drivers/staging/lustre/lustre/include/lustre_fid.h +++ b/drivers/staging/lustre/lustre/include/lustre_fid.h @@ -324,7 +324,7 @@ enum lu_mgr_type { struct lu_client_seq { /* Sequence-controller export. */ struct obd_export *lcs_exp; - struct mutex lcs_mutex; + spinlock_t lcs_lock; /* * Range of allowed for allocation sequences. When using lu_client_seq on diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h index ea158e0630e2..1731048f1ff2 100644 --- a/drivers/staging/lustre/lustre/include/lustre_import.h +++ b/drivers/staging/lustre/lustre/include/lustre_import.h @@ -162,8 +162,8 @@ struct obd_import { struct ptlrpc_client *imp_client; /** List element for linking into pinger chain */ struct list_head imp_pinger_chain; - /** List element for linking into chain for destruction */ - struct list_head imp_zombie_chain; + /** work struct for destruction of import */ + struct work_struct imp_zombie_work; /** * Lists of requests that are retained for replay, waiting for a reply, diff --git a/drivers/staging/lustre/lustre/include/lustre_lib.h b/drivers/staging/lustre/lustre/include/lustre_lib.h index ca1dce15337e..0053eafc1c10 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lib.h +++ b/drivers/staging/lustre/lustre/include/lustre_lib.h @@ -76,281 +76,49 @@ int do_set_info_async(struct obd_import *imp, void target_send_reply(struct ptlrpc_request *req, int rc, int fail_id); -/* - * l_wait_event is a flexible sleeping function, permitting simple caller - * configuration of interrupt and timeout sensitivity along with actions to - * be performed in the event of either exception. - * - * The first form of usage looks like this: - * - * struct l_wait_info lwi = LWI_TIMEOUT_INTR(timeout, timeout_handler, - * intr_handler, callback_data); - * rc = l_wait_event(waitq, condition, &lwi); - * - * l_wait_event() makes the current process wait on 'waitq' until 'condition' - * is TRUE or a "killable" signal (SIGTERM, SIKGILL, SIGINT) is pending. It - * returns 0 to signify 'condition' is TRUE, but if a signal wakes it before - * 'condition' becomes true, it optionally calls the specified 'intr_handler' - * if not NULL, and returns -EINTR. - * - * If a non-zero timeout is specified, signals are ignored until the timeout - * has expired. At this time, if 'timeout_handler' is not NULL it is called. - * If it returns FALSE l_wait_event() continues to wait as described above with - * signals enabled. Otherwise it returns -ETIMEDOUT. - * - * LWI_INTR(intr_handler, callback_data) is shorthand for - * LWI_TIMEOUT_INTR(0, NULL, intr_handler, callback_data) - * - * The second form of usage looks like this: - * - * struct l_wait_info lwi = LWI_TIMEOUT(timeout, timeout_handler); - * rc = l_wait_event(waitq, condition, &lwi); - * - * This form is the same as the first except that it COMPLETELY IGNORES - * SIGNALS. The caller must therefore beware that if 'timeout' is zero, or if - * 'timeout_handler' is not NULL and returns FALSE, then the ONLY thing that - * can unblock the current process is 'condition' becoming TRUE. - * - * Another form of usage is: - * struct l_wait_info lwi = LWI_TIMEOUT_INTERVAL(timeout, interval, - * timeout_handler); - * rc = l_wait_event(waitq, condition, &lwi); - * This is the same as previous case, but condition is checked once every - * 'interval' jiffies (if non-zero). - * - * Subtle synchronization point: this macro does *not* necessary takes - * wait-queue spin-lock before returning, and, hence, following idiom is safe - * ONLY when caller provides some external locking: - * - * Thread1 Thread2 - * - * l_wait_event(&obj->wq, ....); (1) - * - * wake_up(&obj->wq): (2) - * spin_lock(&q->lock); (2.1) - * __wake_up_common(q, ...); (2.2) - * spin_unlock(&q->lock, flags); (2.3) - * - * kfree(obj); (3) - * - * As l_wait_event() may "short-cut" execution and return without taking - * wait-queue spin-lock, some additional synchronization is necessary to - * guarantee that step (3) can begin only after (2.3) finishes. - * - * XXX nikita: some ptlrpc daemon threads have races of that sort. - * - */ -static inline int back_to_sleep(void *arg) -{ - return 0; -} - -#define LWI_ON_SIGNAL_NOOP ((void (*)(void *))(-1)) - -struct l_wait_info { - long lwi_timeout; - long lwi_interval; - int lwi_allow_intr; - int (*lwi_on_timeout)(void *); - void (*lwi_on_signal)(void *); - void *lwi_cb_data; -}; - -/* NB: LWI_TIMEOUT ignores signals completely */ -#define LWI_TIMEOUT(time, cb, data) \ -((struct l_wait_info) { \ - .lwi_timeout = time, \ - .lwi_on_timeout = cb, \ - .lwi_cb_data = data, \ - .lwi_interval = 0, \ - .lwi_allow_intr = 0 \ -}) - -#define LWI_TIMEOUT_INTERVAL(time, interval, cb, data) \ -((struct l_wait_info) { \ - .lwi_timeout = time, \ - .lwi_on_timeout = cb, \ - .lwi_cb_data = data, \ - .lwi_interval = interval, \ - .lwi_allow_intr = 0 \ -}) - -#define LWI_TIMEOUT_INTR(time, time_cb, sig_cb, data) \ -((struct l_wait_info) { \ - .lwi_timeout = time, \ - .lwi_on_timeout = time_cb, \ - .lwi_on_signal = sig_cb, \ - .lwi_cb_data = data, \ - .lwi_interval = 0, \ - .lwi_allow_intr = 0 \ -}) - -#define LWI_TIMEOUT_INTR_ALL(time, time_cb, sig_cb, data) \ -((struct l_wait_info) { \ - .lwi_timeout = time, \ - .lwi_on_timeout = time_cb, \ - .lwi_on_signal = sig_cb, \ - .lwi_cb_data = data, \ - .lwi_interval = 0, \ - .lwi_allow_intr = 1 \ -}) - -#define LWI_INTR(cb, data) LWI_TIMEOUT_INTR(0, NULL, cb, data) - #define LUSTRE_FATAL_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | \ sigmask(SIGTERM) | sigmask(SIGQUIT) | \ sigmask(SIGALRM)) - -/** - * wait_queue_entry_t of Linux (version < 2.6.34) is a FIFO list for exclusively - * waiting threads, which is not always desirable because all threads will - * be waken up again and again, even user only needs a few of them to be - * active most time. This is not good for performance because cache can - * be polluted by different threads. - * - * LIFO list can resolve this problem because we always wakeup the most - * recent active thread by default. - * - * NB: please don't call non-exclusive & exclusive wait on the same - * waitq if add_wait_queue_exclusive_head is used. - */ -#define add_wait_queue_exclusive_head(waitq, link) \ -{ \ - unsigned long flags; \ - \ - spin_lock_irqsave(&((waitq)->lock), flags); \ - __add_wait_queue_exclusive(waitq, link); \ - spin_unlock_irqrestore(&((waitq)->lock), flags); \ +static inline int l_fatal_signal_pending(struct task_struct *p) +{ + return signal_pending(p) && sigtestsetmask(&p->pending.signal, LUSTRE_FATAL_SIGS); } -/* - * wait for @condition to become true, but no longer than timeout, specified - * by @info. - */ -#define __l_wait_event(wq, condition, info, ret, l_add_wait) \ -do { \ - wait_queue_entry_t __wait; \ - long __timeout = info->lwi_timeout; \ - sigset_t __blocked; \ - int __allow_intr = info->lwi_allow_intr; \ - \ - ret = 0; \ - if (condition) \ - break; \ - \ - init_waitqueue_entry(&__wait, current); \ - l_add_wait(&wq, &__wait); \ - \ - /* Block all signals (just the non-fatal ones if no timeout). */ \ - if (info->lwi_on_signal && (__timeout == 0 || __allow_intr)) \ - __blocked = cfs_block_sigsinv(LUSTRE_FATAL_SIGS); \ - else \ - __blocked = cfs_block_sigsinv(0); \ - \ - for (;;) { \ - if (condition) \ - break; \ - \ - set_current_state(TASK_INTERRUPTIBLE); \ - \ - if (__timeout == 0) { \ - schedule(); \ - } else { \ - long interval = info->lwi_interval ? \ - min_t(long, \ - info->lwi_interval, __timeout) : \ - __timeout; \ - long remaining = schedule_timeout(interval);\ - __timeout = cfs_time_sub(__timeout, \ - cfs_time_sub(interval, remaining));\ - if (__timeout == 0) { \ - if (!info->lwi_on_timeout || \ - info->lwi_on_timeout(info->lwi_cb_data)) { \ - ret = -ETIMEDOUT; \ - break; \ - } \ - /* Take signals after the timeout expires. */ \ - if (info->lwi_on_signal) \ - (void)cfs_block_sigsinv(LUSTRE_FATAL_SIGS);\ - } \ - } \ - \ - set_current_state(TASK_RUNNING); \ - \ - if (condition) \ - break; \ - if (signal_pending(current)) { \ - if (info->lwi_on_signal && \ - (__timeout == 0 || __allow_intr)) { \ - if (info->lwi_on_signal != LWI_ON_SIGNAL_NOOP) \ - info->lwi_on_signal(info->lwi_cb_data);\ - ret = -EINTR; \ - break; \ - } \ - /* We have to do this here because some signals */ \ - /* are not blockable - ie from strace(1). */ \ - /* In these cases we want to schedule_timeout() */ \ - /* again, because we don't want that to return */ \ - /* -EINTR when the RPC actually succeeded. */ \ - /* the recalc_sigpending() below will deliver the */ \ - /* signal properly. */ \ - cfs_clear_sigpending(); \ - } \ - } \ - \ - cfs_restore_sigs(__blocked); \ - \ - remove_wait_queue(&wq, &__wait); \ -} while (0) - -#define l_wait_event(wq, condition, info) \ -({ \ - int __ret; \ - struct l_wait_info *__info = (info); \ - \ - __l_wait_event(wq, condition, __info, \ - __ret, add_wait_queue); \ - __ret; \ -}) +/** @} lib */ -#define l_wait_event_exclusive(wq, condition, info) \ -({ \ - int __ret; \ - struct l_wait_info *__info = (info); \ - \ - __l_wait_event(wq, condition, __info, \ - __ret, add_wait_queue_exclusive); \ - __ret; \ -}) -#define l_wait_event_exclusive_head(wq, condition, info) \ -({ \ - int __ret; \ - struct l_wait_info *__info = (info); \ - \ - __l_wait_event(wq, condition, __info, \ - __ret, add_wait_queue_exclusive_head); \ - __ret; \ -}) -#define l_wait_condition(wq, condition) \ -({ \ - struct l_wait_info lwi = { 0 }; \ - l_wait_event(wq, condition, &lwi); \ +/* l_wait_event_abortable() is a bit like wait_event_killable() + * except there is a fixed set of signals which will abort: + * LUSTRE_FATAL_SIGS + */ +#define l_wait_event_abortable(wq, condition) \ +({ \ + sigset_t __old_blocked; \ + int __ret = 0; \ + cfs_block_sigsinv(LUSTRE_FATAL_SIGS, &__old_blocked); \ + __ret = wait_event_interruptible(wq, condition); \ + cfs_restore_sigs(&__old_blocked); \ + __ret; \ }) -#define l_wait_condition_exclusive(wq, condition) \ -({ \ - struct l_wait_info lwi = { 0 }; \ - l_wait_event_exclusive(wq, condition, &lwi); \ +#define l_wait_event_abortable_timeout(wq, condition, timeout) \ +({ \ + sigset_t __old_blocked; \ + int __ret = 0; \ + cfs_block_sigsinv(LUSTRE_FATAL_SIGS, &__old_blocked); \ + __ret = wait_event_interruptible_timeout(wq, condition, timeout);\ + cfs_restore_sigs(&__old_blocked); \ + __ret; \ }) -#define l_wait_condition_exclusive_head(wq, condition) \ -({ \ - struct l_wait_info lwi = { 0 }; \ - l_wait_event_exclusive_head(wq, condition, &lwi); \ +#define l_wait_event_abortable_exclusive(wq, condition) \ +({ \ + sigset_t __old_blocked; \ + int __ret = 0; \ + cfs_block_sigsinv(LUSTRE_FATAL_SIGS, &__old_blocked); \ + __ret = wait_event_interruptible_exclusive(wq, condition); \ + cfs_restore_sigs(&__old_blocked); \ + __ret; \ }) - -/** @} lib */ - #endif /* _LUSTRE_LIB_H */ diff --git a/drivers/staging/lustre/lustre/include/lustre_lmv.h b/drivers/staging/lustre/lustre/include/lustre_lmv.h index f4298e5f7543..080ec1f8e19f 100644 --- a/drivers/staging/lustre/lustre/include/lustre_lmv.h +++ b/drivers/staging/lustre/lustre/include/lustre_lmv.h @@ -63,7 +63,7 @@ lsm_md_eq(const struct lmv_stripe_md *lsm1, const struct lmv_stripe_md *lsm2) lsm1->lsm_md_master_mdt_index != lsm2->lsm_md_master_mdt_index || lsm1->lsm_md_hash_type != lsm2->lsm_md_hash_type || lsm1->lsm_md_layout_version != lsm2->lsm_md_layout_version || - !strcmp(lsm1->lsm_md_pool_name, lsm2->lsm_md_pool_name)) + strcmp(lsm1->lsm_md_pool_name, lsm2->lsm_md_pool_name) != 0) return false; for (idx = 0; idx < lsm1->lsm_md_stripe_count; idx++) { diff --git a/drivers/staging/lustre/lustre/include/lustre_mdc.h b/drivers/staging/lustre/lustre/include/lustre_mdc.h index 007e1ec3f0f4..a9c9992a2502 100644 --- a/drivers/staging/lustre/lustre/include/lustre_mdc.h +++ b/drivers/staging/lustre/lustre/include/lustre_mdc.h @@ -124,7 +124,7 @@ static inline void mdc_get_rpc_lock(struct mdc_rpc_lock *lck, */ while (unlikely(lck->rpcl_it == MDC_FAKE_RPCL_IT)) { mutex_unlock(&lck->rpcl_mutex); - schedule_timeout(cfs_time_seconds(1) / 4); + schedule_timeout(HZ / 4); goto again; } diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index 3ff5de4770e8..d35ae0cda8d2 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -1259,8 +1259,6 @@ enum { SVC_STOPPING = 1 << 1, SVC_STARTING = 1 << 2, SVC_RUNNING = 1 << 3, - SVC_EVENT = 1 << 4, - SVC_SIGNAL = 1 << 5, }; #define PTLRPC_THR_NAME_LEN 32 @@ -1303,11 +1301,6 @@ struct ptlrpc_thread { char t_name[PTLRPC_THR_NAME_LEN]; }; -static inline int thread_is_init(struct ptlrpc_thread *thread) -{ - return thread->t_flags == 0; -} - static inline int thread_is_stopped(struct ptlrpc_thread *thread) { return !!(thread->t_flags & SVC_STOPPED); @@ -1328,16 +1321,6 @@ static inline int thread_is_running(struct ptlrpc_thread *thread) return !!(thread->t_flags & SVC_RUNNING); } -static inline int thread_is_event(struct ptlrpc_thread *thread) -{ - return !!(thread->t_flags & SVC_EVENT); -} - -static inline int thread_is_signal(struct ptlrpc_thread *thread) -{ - return !!(thread->t_flags & SVC_SIGNAL); -} - static inline void thread_clear_flags(struct ptlrpc_thread *thread, __u32 flags) { thread->t_flags &= ~flags; @@ -1821,6 +1804,9 @@ int ptlrpc_register_rqbd(struct ptlrpc_request_buffer_desc *rqbd); */ void ptlrpc_request_committed(struct ptlrpc_request *req, int force); +int ptlrpc_inc_ref(void); +void ptlrpc_dec_ref(void); + void ptlrpc_init_client(int req_portal, int rep_portal, char *name, struct ptlrpc_client *); struct ptlrpc_connection *ptlrpc_uuid_to_connection(struct obd_uuid *uuid); @@ -2268,7 +2254,7 @@ static inline int ptlrpc_send_limit_expired(struct ptlrpc_request *req) { if (req->rq_delay_limit != 0 && time_before(cfs_time_add(req->rq_queued_time, - cfs_time_seconds(req->rq_delay_limit)), + req->rq_delay_limit * HZ), cfs_time_current())) { return 1; } diff --git a/drivers/staging/lustre/lustre/include/lustre_sec.h b/drivers/staging/lustre/lustre/include/lustre_sec.h index 64b6fd4fed8f..c5cb07acd0da 100644 --- a/drivers/staging/lustre/lustre/include/lustre_sec.h +++ b/drivers/staging/lustre/lustre/include/lustre_sec.h @@ -1058,9 +1058,6 @@ int sptlrpc_current_user_desc_size(void); int sptlrpc_pack_user_desc(struct lustre_msg *msg, int offset); int sptlrpc_unpack_user_desc(struct lustre_msg *req, int offset, int swabbed); -#define CFS_CAP_CHOWN_MASK (1 << CFS_CAP_CHOWN) -#define CFS_CAP_SYS_RESOURCE_MASK (1 << CFS_CAP_SYS_RESOURCE) - enum { LUSTRE_SEC_NONE = 0, LUSTRE_SEC_REMOTE = 1, diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 4368f4e9f208..f1233ca7d337 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -191,7 +191,7 @@ struct client_obd { struct sptlrpc_flavor cl_flvr_mgc; /* fixed flavor of mgc->mgs */ /* the grant values are protected by loi_list_lock below */ - unsigned long cl_dirty_pages; /* all _dirty_ in pahges */ + unsigned long cl_dirty_pages; /* all _dirty_ in pages */ unsigned long cl_dirty_max_pages; /* allowed w/o rpc */ unsigned long cl_dirty_transit; /* dirty synchronous */ unsigned long cl_avail_grant; /* bytes of credit for ost */ diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 531e8ddfa9e5..f24dd74ffa09 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -294,10 +294,10 @@ struct obdo; void obdo_to_ioobj(const struct obdo *oa, struct obd_ioobj *ioobj); -#define OBT(dev) (dev)->obd_type -#define OBP(dev, op) (dev)->obd_type->typ_dt_ops->op -#define MDP(dev, op) (dev)->obd_type->typ_md_ops->op -#define CTXTP(ctxt, op) (ctxt)->loc_logops->lop_##op +#define OBT(dev) ((dev)->obd_type) +#define OBP(dev, op) ((dev)->obd_type->typ_dt_ops->op) +#define MDP(dev, op) ((dev)->obd_type->typ_md_ops->op) +#define CTXTP(ctxt, op) ((ctxt)->loc_logops->lop_##op) /* * Ensure obd_setup: used for cleanup which must be called diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index 3f4fe290f6ea..8595091b8b86 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -516,7 +516,7 @@ extern char obd_jobid_var[]; #define POISON_PTR(ptr) ((void)0) #else #define POISON(ptr, c, s) memset(ptr, c, s) -#define POISON_PTR(ptr) (ptr) = (void *)0xdeadbeef +#define POISON_PTR(ptr) ((ptr) = (void *)0xdeadbeef) #endif #ifdef POISON_BULK diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c index 657ab95091a0..411b540b96d9 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_flock.c @@ -310,24 +310,6 @@ reprocess: return LDLM_ITER_CONTINUE; } -struct ldlm_flock_wait_data { - struct ldlm_lock *fwd_lock; -}; - -static void -ldlm_flock_interrupted_wait(void *data) -{ - struct ldlm_lock *lock; - - lock = ((struct ldlm_flock_wait_data *)data)->fwd_lock; - - lock_res_and_lock(lock); - - /* client side - set flag to prevent lock from being put on LRU list */ - ldlm_set_cbpending(lock); - unlock_res_and_lock(lock); -} - /** * Flock completion callback function. * @@ -342,8 +324,6 @@ int ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data) { struct file_lock *getlk = lock->l_ast_data; - struct ldlm_flock_wait_data fwd; - struct l_wait_info lwi; int rc = 0; OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CP_CB_WAIT2, 4); @@ -372,13 +352,17 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data) LDLM_DEBUG(lock, "client-side enqueue returned a blocked lock, sleeping"); - fwd.fwd_lock = lock; - lwi = LWI_TIMEOUT_INTR(0, NULL, ldlm_flock_interrupted_wait, &fwd); /* Go to sleep until the lock is granted. */ - rc = l_wait_event(lock->l_waitq, is_granted_or_cancelled(lock), &lwi); + rc = l_wait_event_abortable(lock->l_waitq, is_granted_or_cancelled(lock)); if (rc) { + lock_res_and_lock(lock); + + /* client side - set flag to prevent lock from being put on LRU list */ + ldlm_set_cbpending(lock); + unlock_res_and_lock(lock); + LDLM_DEBUG(lock, "client-side enqueue waking up: failed (%d)", rc); return rc; diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index 7cbc6a06afec..95bea351d21d 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -1349,7 +1349,6 @@ out: if ((flags & LDLM_FL_LVB_READY) && !ldlm_is_lvb_ready(lock)) { __u64 wait_flags = LDLM_FL_LVB_READY | LDLM_FL_DESTROYED | LDLM_FL_FAIL_NOTIFIED; - struct l_wait_info lwi; if (lock->l_completion_ast) { int err = lock->l_completion_ast(lock, @@ -1366,13 +1365,10 @@ out: } } - lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(obd_timeout), - NULL, LWI_ON_SIGNAL_NOOP, NULL); - /* XXX FIXME see comment on CAN_MATCH in lustre_dlm.h */ - l_wait_event(lock->l_waitq, - lock->l_flags & wait_flags, - &lwi); + wait_event_idle_timeout(lock->l_waitq, + lock->l_flags & wait_flags, + obd_timeout * HZ); if (!ldlm_is_lvb_ready(lock)) { if (flags & LDLM_FL_TEST_LOCK) LDLM_LOCK_RELEASE(lock); @@ -1913,14 +1909,12 @@ void ldlm_cancel_callback(struct ldlm_lock *lock) ldlm_set_bl_done(lock); wake_up_all(&lock->l_waitq); } else if (!ldlm_is_bl_done(lock)) { - struct l_wait_info lwi = { 0 }; - /* * The lock is guaranteed to have been canceled once * returning from this function. */ unlock_res_and_lock(lock); - l_wait_event(lock->l_waitq, is_bl_done(lock), &lwi); + wait_event_idle(lock->l_waitq, is_bl_done(lock)); lock_res_and_lock(lock); } } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 5f6e7c933b81..c772c68e5a49 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -163,7 +163,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req, LDLM_DEBUG(lock, "client completion callback handler START"); if (OBD_FAIL_CHECK(OBD_FAIL_LDLM_CANCEL_BL_CB_RACE)) { - int to = cfs_time_seconds(1); + int to = HZ; while (to > 0) { set_current_state(TASK_INTERRUPTIBLE); @@ -327,7 +327,7 @@ static void ldlm_handle_gl_callback(struct ptlrpc_request *req, !lock->l_readers && !lock->l_writers && cfs_time_after(cfs_time_current(), cfs_time_add(lock->l_last_used, - cfs_time_seconds(10)))) { + 10 * HZ))) { unlock_res_and_lock(lock); if (ldlm_bl_to_thread_lock(ns, NULL, lock)) ldlm_handle_bl_callback(ns, NULL, lock); @@ -833,17 +833,15 @@ static int ldlm_bl_thread_main(void *arg) /* cannot use bltd after this, it is only on caller's stack */ while (1) { - struct l_wait_info lwi = { 0 }; struct ldlm_bl_work_item *blwi = NULL; struct obd_export *exp = NULL; int rc; rc = ldlm_bl_get_work(blp, &blwi, &exp); if (!rc) - l_wait_event_exclusive(blp->blp_waitq, - ldlm_bl_get_work(blp, &blwi, - &exp), - &lwi); + wait_event_idle_exclusive(blp->blp_waitq, + ldlm_bl_get_work(blp, &blwi, + &exp)); atomic_inc(&blp->blp_busy_threads); if (ldlm_bl_thread_need_create(blp, blwi)) @@ -871,6 +869,10 @@ int ldlm_get_ref(void) { int rc = 0; + rc = ptlrpc_inc_ref(); + if (rc) + return rc; + mutex_lock(&ldlm_ref_mutex); if (++ldlm_refcount == 1) { rc = ldlm_setup(); @@ -879,14 +881,18 @@ int ldlm_get_ref(void) } mutex_unlock(&ldlm_ref_mutex); + if (rc) + ptlrpc_dec_ref(); + return rc; } void ldlm_put_ref(void) { + int rc = 0; mutex_lock(&ldlm_ref_mutex); if (ldlm_refcount == 1) { - int rc = ldlm_cleanup(); + rc = ldlm_cleanup(); if (rc) CERROR("ldlm_cleanup failed: %d\n", rc); @@ -896,6 +902,8 @@ void ldlm_put_ref(void) ldlm_refcount--; } mutex_unlock(&ldlm_ref_mutex); + if (!rc) + ptlrpc_dec_ref(); } static ssize_t cancel_unused_locks_before_replay_show(struct kobject *kobj, diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c index 8563bd32befa..53b8f33e54b5 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c @@ -784,9 +784,6 @@ static int ldlm_pool_granted(struct ldlm_pool *pl) return atomic_read(&pl->pl_granted); } -static struct ptlrpc_thread *ldlm_pools_thread; -static struct completion ldlm_pools_comp; - /* * count locks from all namespaces (if possible). Returns number of * cached locks. @@ -899,8 +896,12 @@ static unsigned long ldlm_pools_cli_scan(struct shrinker *s, sc->gfp_mask); } -static int ldlm_pools_recalc(enum ldlm_side client) +static void ldlm_pools_recalc(struct work_struct *ws); +static DECLARE_DELAYED_WORK(ldlm_recalc_pools, ldlm_pools_recalc); + +static void ldlm_pools_recalc(struct work_struct *ws) { + enum ldlm_side client = LDLM_NAMESPACE_CLIENT; struct ldlm_namespace *ns; struct ldlm_namespace *ns_old = NULL; /* seconds of sleep if no active namespaces */ @@ -982,97 +983,19 @@ static int ldlm_pools_recalc(enum ldlm_side client) /* Wake up the blocking threads from time to time. */ ldlm_bl_thread_wakeup(); - return time; -} - -static int ldlm_pools_thread_main(void *arg) -{ - struct ptlrpc_thread *thread = (struct ptlrpc_thread *)arg; - int c_time; - - thread_set_flags(thread, SVC_RUNNING); - wake_up(&thread->t_ctl_waitq); - - CDEBUG(D_DLMTRACE, "%s: pool thread starting, process %d\n", - "ldlm_poold", current_pid()); - - while (1) { - struct l_wait_info lwi; - - /* - * Recal all pools on this tick. - */ - c_time = ldlm_pools_recalc(LDLM_NAMESPACE_CLIENT); - - /* - * Wait until the next check time, or until we're - * stopped. - */ - lwi = LWI_TIMEOUT(cfs_time_seconds(c_time), - NULL, NULL); - l_wait_event(thread->t_ctl_waitq, - thread_is_stopping(thread) || - thread_is_event(thread), - &lwi); - - if (thread_test_and_clear_flags(thread, SVC_STOPPING)) - break; - thread_test_and_clear_flags(thread, SVC_EVENT); - } - - thread_set_flags(thread, SVC_STOPPED); - wake_up(&thread->t_ctl_waitq); - - CDEBUG(D_DLMTRACE, "%s: pool thread exiting, process %d\n", - "ldlm_poold", current_pid()); - - complete_and_exit(&ldlm_pools_comp, 0); + schedule_delayed_work(&ldlm_recalc_pools, time * HZ); } static int ldlm_pools_thread_start(void) { - struct l_wait_info lwi = { 0 }; - struct task_struct *task; - - if (ldlm_pools_thread) - return -EALREADY; - - ldlm_pools_thread = kzalloc(sizeof(*ldlm_pools_thread), GFP_NOFS); - if (!ldlm_pools_thread) - return -ENOMEM; - - init_completion(&ldlm_pools_comp); - init_waitqueue_head(&ldlm_pools_thread->t_ctl_waitq); + schedule_delayed_work(&ldlm_recalc_pools, 0); - task = kthread_run(ldlm_pools_thread_main, ldlm_pools_thread, - "ldlm_poold"); - if (IS_ERR(task)) { - CERROR("Can't start pool thread, error %ld\n", PTR_ERR(task)); - kfree(ldlm_pools_thread); - ldlm_pools_thread = NULL; - return PTR_ERR(task); - } - l_wait_event(ldlm_pools_thread->t_ctl_waitq, - thread_is_running(ldlm_pools_thread), &lwi); return 0; } static void ldlm_pools_thread_stop(void) { - if (!ldlm_pools_thread) - return; - - thread_set_flags(ldlm_pools_thread, SVC_STOPPING); - wake_up(&ldlm_pools_thread->t_ctl_waitq); - - /* - * Make sure that pools thread is finished before freeing @thread. - * This fixes possible race and oops due to accessing freed memory - * in pools thread. - */ - wait_for_completion(&ldlm_pools_comp); - kfree(ldlm_pools_thread); - ldlm_pools_thread = NULL; + cancel_delayed_work_sync(&ldlm_recalc_pools); } static struct shrinker ldlm_pools_cli_shrinker = { @@ -1086,20 +1009,15 @@ int ldlm_pools_init(void) int rc; rc = ldlm_pools_thread_start(); - if (rc) - return rc; - - rc = register_shrinker(&ldlm_pools_cli_shrinker); - if (rc) - ldlm_pools_thread_stop(); + if (!rc) + rc = register_shrinker(&ldlm_pools_cli_shrinker); return rc; } void ldlm_pools_fini(void) { - if (ldlm_pools_thread) - unregister_shrinker(&ldlm_pools_cli_shrinker); + unregister_shrinker(&ldlm_pools_cli_shrinker); ldlm_pools_thread_stop(); } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index 6aa37463db46..c3c9186b74ce 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -72,15 +72,6 @@ MODULE_PARM_DESC(ldlm_enqueue_min, "lock enqueue timeout minimum"); /* in client side, whether the cached locks will be canceled before replay */ unsigned int ldlm_cancel_unused_locks_before_replay = 1; -static void interrupted_completion_wait(void *data) -{ -} - -struct lock_wait_data { - struct ldlm_lock *lwd_lock; - __u32 lwd_conn_cnt; -}; - struct ldlm_async_args { struct lustre_handle lock_handle; }; @@ -112,10 +103,8 @@ static int ldlm_request_bufsize(int count, int type) return sizeof(struct ldlm_request) + avail; } -static int ldlm_expired_completion_wait(void *data) +static void ldlm_expired_completion_wait(struct ldlm_lock *lock, __u32 conn_cnt) { - struct lock_wait_data *lwd = data; - struct ldlm_lock *lock = lwd->lwd_lock; struct obd_import *imp; struct obd_device *obd; @@ -135,19 +124,17 @@ static int ldlm_expired_completion_wait(void *data) if (last_dump == 0) libcfs_debug_dumplog(); } - return 0; + return; } obd = lock->l_conn_export->exp_obd; imp = obd->u.cli.cl_import; - ptlrpc_fail_import(imp, lwd->lwd_conn_cnt); + ptlrpc_fail_import(imp, conn_cnt); LDLM_ERROR(lock, "lock timed out (enqueued at %lld, %llds ago), entering recovery for %s@%s", (s64)lock->l_last_activity, (s64)(ktime_get_real_seconds() - lock->l_last_activity), obd2cli_tgt(obd), imp->imp_connection->c_remote_uuid.uuid); - - return 0; } /** @@ -251,11 +238,10 @@ EXPORT_SYMBOL(ldlm_completion_ast_async); int ldlm_completion_ast(struct ldlm_lock *lock, __u64 flags, void *data) { /* XXX ALLOCATE - 160 bytes */ - struct lock_wait_data lwd; struct obd_device *obd; struct obd_import *imp = NULL; - struct l_wait_info lwi; __u32 timeout; + __u32 conn_cnt = 0; int rc = 0; if (flags == LDLM_FL_WAIT_NOREPROC) { @@ -281,32 +267,33 @@ noreproc: timeout = ldlm_cp_timeout(lock); - lwd.lwd_lock = lock; lock->l_last_activity = ktime_get_real_seconds(); - if (ldlm_is_no_timeout(lock)) { - LDLM_DEBUG(lock, "waiting indefinitely because of NO_TIMEOUT"); - lwi = LWI_INTR(interrupted_completion_wait, &lwd); - } else { - lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout), - ldlm_expired_completion_wait, - interrupted_completion_wait, &lwd); - } - if (imp) { spin_lock(&imp->imp_lock); - lwd.lwd_conn_cnt = imp->imp_conn_cnt; + conn_cnt = imp->imp_conn_cnt; spin_unlock(&imp->imp_lock); } - if (OBD_FAIL_CHECK_RESET(OBD_FAIL_LDLM_INTR_CP_AST, OBD_FAIL_LDLM_CP_BL_RACE | OBD_FAIL_ONCE)) { ldlm_set_fail_loc(lock); rc = -EINTR; } else { - /* Go to sleep until the lock is granted or cancelled. */ - rc = l_wait_event(lock->l_waitq, - is_granted_or_cancelled(lock), &lwi); + /* Go to sleep until the lock is granted or canceled. */ + if (!ldlm_is_no_timeout(lock)) { + /* Wait uninterruptible for a while first */ + rc = wait_event_idle_timeout(lock->l_waitq, + is_granted_or_cancelled(lock), + timeout * HZ); + if (rc == 0) + ldlm_expired_completion_wait(lock, conn_cnt); + } + /* Now wait abortable */ + if (rc == 0) + rc = l_wait_event_abortable(lock->l_waitq, + is_granted_or_cancelled(lock)); + else + rc = 0; } if (rc) { diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index 9958533cc227..4c44603ab6f9 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -799,7 +799,7 @@ static void cleanup_resource(struct ldlm_resource *res, struct list_head *q, LDLM_DEBUG(lock, "setting FL_LOCAL_ONLY"); if (lock->l_flags & LDLM_FL_FAIL_LOC) { set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(4)); + schedule_timeout(4 * HZ); set_current_state(TASK_RUNNING); } if (lock->l_completion_ast) @@ -879,7 +879,6 @@ static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force) ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0); if (atomic_read(&ns->ns_bref) > 0) { - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); int rc; CDEBUG(D_DLMTRACE, @@ -887,11 +886,12 @@ static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force) ldlm_ns_name(ns), atomic_read(&ns->ns_bref)); force_wait: if (force) - lwi = LWI_TIMEOUT(msecs_to_jiffies(obd_timeout * - MSEC_PER_SEC) / 4, NULL, NULL); - - rc = l_wait_event(ns->ns_waitq, - atomic_read(&ns->ns_bref) == 0, &lwi); + rc = wait_event_idle_timeout(ns->ns_waitq, + atomic_read(&ns->ns_bref) == 0, + obd_timeout * HZ / 4) ? 0 : -ETIMEDOUT; + else + rc = l_wait_event_abortable(ns->ns_waitq, + atomic_read(&ns->ns_bref) == 0); /* Forced cleanups should be able to reclaim all references, * so it's safe to wait forever... we can't leak locks... diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 6cd0318062e8..11b82c639bfe 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -74,6 +74,12 @@ static void ll_release(struct dentry *de) * an AST before calling d_revalidate_it(). The dentry still exists (marked * INVALID) so d_lookup() matches it, but we have no lock on it (so * lock_match() fails) and we spin around real_lookup(). + * + * This race doesn't apply to lookups in d_alloc_parallel(), and for + * those we want to ensure that only one dentry with a given name is + * in ll_lookup_nd() at a time. So allow invalid dentries to match + * while d_in_lookup(). We will be called again when the lookup + * completes, and can give a different answer then. */ static int ll_dcompare(const struct dentry *dentry, unsigned int len, const char *str, @@ -93,6 +99,10 @@ static int ll_dcompare(const struct dentry *dentry, if (d_mountpoint(dentry)) return 0; + /* ensure exclusion against parallel lookup of the same name */ + if (d_in_lookup((struct dentry *)dentry)) + return 0; + if (d_lustre_invalid(dentry)) return 1; diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 99b0b77c75f5..d10d27268323 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -885,7 +885,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) switch (cmd) { case Q_SETQUOTA: case Q_SETINFO: - if (!capable(CFS_CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; break; case Q_GETQUOTA: @@ -893,7 +893,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) || (type == GRPQUOTA && !in_egroup_p(make_kgid(&init_user_ns, id)))) && - !capable(CFS_CAP_SYS_ADMIN)) + !capable(CAP_SYS_ADMIN)) return -EPERM; break; case Q_GETINFO: @@ -1452,7 +1452,7 @@ out_quotactl: } case OBD_IOC_CHANGELOG_SEND: case OBD_IOC_CHANGELOG_CLEAR: - if (!capable(CFS_CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void __user *)arg, @@ -1497,7 +1497,7 @@ out_quotactl: if (totalsize >= MDS_MAXREQSIZE / 3) return -E2BIG; - hur = libcfs_kvzalloc(totalsize, GFP_NOFS); + hur = kzalloc(totalsize, GFP_NOFS); if (!hur) return -ENOMEM; @@ -1556,7 +1556,7 @@ out_quotactl: return rc; } case LL_IOC_HSM_CT_START: - if (!capable(CFS_CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void __user *)arg, diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 938b859b6650..ca5faea13b7e 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -1315,10 +1315,10 @@ static int ll_lov_setea(struct inode *inode, struct file *file, sizeof(struct lov_user_ost_data); int rc; - if (!capable(CFS_CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lump = libcfs_kvzalloc(lum_size, GFP_NOFS); + lump = kzalloc(lum_size, GFP_NOFS); if (!lump) return -ENOMEM; @@ -1570,7 +1570,7 @@ int ll_fid2path(struct inode *inode, void __user *arg) size_t outsize; int rc; - if (!capable(CFS_CAP_DAC_READ_SEARCH) && + if (!capable(CAP_DAC_READ_SEARCH) && !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH)) return -EPERM; @@ -1840,7 +1840,7 @@ int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss) * NOT defined in HSM_USER_MASK. */ if (((hss->hss_setmask | hss->hss_clearmask) & ~HSM_USER_MASK) && - !capable(CFS_CAP_SYS_ADMIN)) + !capable(CAP_SYS_ADMIN)) return -EPERM; /* Detect out-of range archive id */ @@ -2998,7 +2998,7 @@ static int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, num_bytes = sizeof(*fiemap) + (extent_count * sizeof(struct fiemap_extent)); - fiemap = libcfs_kvzalloc(num_bytes, GFP_NOFS); + fiemap = kvzalloc(num_bytes, GFP_KERNEL); if (!fiemap) return -ENOMEM; @@ -3361,7 +3361,7 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) goto out; } - lvbdata = libcfs_kvzalloc(lmmsize, GFP_NOFS); + lvbdata = kvzalloc(lmmsize, GFP_NOFS); if (!lvbdata) { rc = -ENOMEM; goto out; diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index f68c2e88f12b..d46bcf71b273 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -1070,8 +1070,8 @@ struct ll_statahead_info { sai_agl_valid:1,/* AGL is valid for the dir */ sai_in_readpage:1;/* statahead in readdir() */ wait_queue_head_t sai_waitq; /* stat-ahead wait queue */ - struct ptlrpc_thread sai_thread; /* stat-ahead thread */ - struct ptlrpc_thread sai_agl_thread; /* AGL thread */ + struct task_struct *sai_task; /* stat-ahead thread */ + struct task_struct *sai_agl_task; /* AGL thread */ struct list_head sai_interim_entries; /* entries which got async * stat reply, but not * instantiated diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 6735a6f006d2..e7500c53fafc 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -879,9 +879,15 @@ int ll_fill_super(struct super_block *sb) CDEBUG(D_VFSTRACE, "VFS Op: sb %p\n", sb); + err = ptlrpc_inc_ref(); + if (err) + return err; + cfg = kzalloc(sizeof(*cfg), GFP_NOFS); - if (!cfg) - return -ENOMEM; + if (!cfg) { + err = -ENOMEM; + goto out_put; + } try_module_get(THIS_MODULE); @@ -891,7 +897,8 @@ int ll_fill_super(struct super_block *sb) if (!sbi) { module_put(THIS_MODULE); kfree(cfg); - return -ENOMEM; + err = -ENOMEM; + goto out_put; } err = ll_options(lsi->lsi_lmd->lmd_opts, &sbi->ll_flags); @@ -958,6 +965,9 @@ out_free: LCONSOLE_WARN("Mounted %s\n", profilenm); kfree(cfg); +out_put: + if (err) + ptlrpc_dec_ref(); return err; } /* ll_fill_super */ @@ -986,16 +996,12 @@ void ll_put_super(struct super_block *sb) } /* Wait for unstable pages to be committed to stable storage */ - if (!force) { - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); - - rc = l_wait_event(sbi->ll_cache->ccc_unstable_waitq, - !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr), - &lwi); - } + if (!force) + rc = l_wait_event_abortable(sbi->ll_cache->ccc_unstable_waitq, + !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr)); ccc_count = atomic_long_read(&sbi->ll_cache->ccc_unstable_nr); - if (!force && rc != -EINTR) + if (!force && rc != -ERESTARTSYS) LASSERTF(!ccc_count, "count: %li\n", ccc_count); /* We need to set force before the lov_disconnect in @@ -1032,6 +1038,8 @@ void ll_put_super(struct super_block *sb) cl_env_cache_purge(~0); module_put(THIS_MODULE); + + ptlrpc_dec_ref(); } /* client_put_super */ struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock) @@ -1197,13 +1205,12 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md) lmv_free_memmd(lli->lli_lsm_md); lli->lli_lsm_md = NULL; return 0; - } else { - /* - * The lustre_md from req does not include stripeEA, - * see ll_md_setattr - */ - return 0; } + /* + * The lustre_md from req does not include stripeEA, + * see ll_md_setattr + */ + return 0; } /* set the directory layout */ @@ -1454,7 +1461,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) /* POSIX: check before ATTR_*TIME_SET set (from setattr_prepare) */ if (attr->ia_valid & TIMES_SET_FLAGS) { if ((!uid_eq(current_fsuid(), inode->i_uid)) && - !capable(CFS_CAP_FOWNER)) + !capable(CAP_FOWNER)) return -EPERM; } @@ -1988,8 +1995,7 @@ void ll_umount_begin(struct super_block *sb) struct ll_sb_info *sbi = ll_s2sbi(sb); struct obd_device *obd; struct obd_ioctl_data *ioc_data; - wait_queue_head_t waitq; - struct l_wait_info lwi; + int cnt = 0; CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb, sb->s_count, atomic_read(&sb->s_active)); @@ -2025,10 +2031,10 @@ void ll_umount_begin(struct super_block *sb) * and then continue. For now, we just periodically checking for vfs * to decrement mnt_cnt and hope to finish it within 10sec. */ - init_waitqueue_head(&waitq); - lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(10), - cfs_time_seconds(1), NULL, NULL); - l_wait_event(waitq, may_umount(sbi->ll_mnt.mnt), &lwi); + while (cnt < 10 && !may_umount(sbi->ll_mnt.mnt)) { + schedule_timeout_uninterruptible(HZ); + cnt++; + } schedule(); } @@ -2143,7 +2149,7 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, md.posix_acl = NULL; } #endif - rc = -ENOMEM; + rc = PTR_ERR(*inode); CERROR("new_inode -fatal: rc %d\n", rc); goto out; } @@ -2602,7 +2608,7 @@ int ll_getparent(struct file *file, struct getparent __user *arg) u32 linkno; int rc; - if (!capable(CFS_CAP_DAC_READ_SEARCH) && + if (!capable(CAP_DAC_READ_SEARCH) && !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH)) return -EPERM; @@ -2653,7 +2659,7 @@ int ll_getparent(struct file *file, struct getparent __user *arg) } lb_free: - lu_buf_free(&buf); + kvfree(buf.lb_buf); ldata_free: kfree(ldata); return rc; diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index c0533bd6f352..214b07554e62 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -177,14 +177,14 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage, vio->u.fault.ft_vma = vma; vio->u.fault.ft_vmpage = vmpage; - set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM)); + cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM), &set); inode = vvp_object_inode(io->ci_obj); lli = ll_i2info(inode); result = cl_io_loop(env, io); - cfs_restore_sigs(set); + cfs_restore_sigs(&set); if (result == 0) { struct inode *inode = file_inode(vma->vm_file); @@ -334,7 +334,7 @@ static int ll_fault(struct vm_fault *vmf) * so that it can be killed by admin but not cause segfault by * other signals. */ - set = cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM)); + cfs_block_sigsinv(sigmask(SIGKILL) | sigmask(SIGTERM), &set); restart: result = ll_fault0(vmf->vma, vmf); @@ -360,7 +360,7 @@ restart: result = VM_FAULT_LOCKED; } - cfs_restore_sigs(set); + cfs_restore_sigs(&set); return result; } diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index a2687f46a16d..6c9ec462eb41 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -380,52 +380,45 @@ void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2) } /* - * try to reuse three types of dentry: - * 1. unhashed alias, this one is unhashed by d_invalidate (but it may be valid - * by concurrent .revalidate). - * 2. INVALID alias (common case for no valid ldlm lock held, but this flag may - * be cleared by others calling d_lustre_revalidate). - * 3. DISCONNECTED alias. + * Try to reuse unhashed or invalidated dentries. + * This is very similar to d_exact_alias(), and any changes in one should be + * considered for inclusion in the other. The differences are that we don't + * need an unhashed alias, and we don't want d_compare to be used for + * comparison. */ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry) { - struct dentry *alias, *discon_alias, *invalid_alias; + struct dentry *alias; if (hlist_empty(&inode->i_dentry)) return NULL; - discon_alias = NULL; - invalid_alias = NULL; - spin_lock(&inode->i_lock); hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { LASSERT(alias != dentry); + /* + * Don't need alias->d_lock here, because aliases with + * d_parent == entry->d_parent are not subject to name or + * parent changes, because the parent inode i_mutex is held. + */ - spin_lock(&alias->d_lock); - if ((alias->d_flags & DCACHE_DISCONNECTED) && - S_ISDIR(inode->i_mode)) - /* LASSERT(last_discon == NULL); LU-405, bz 20055 */ - discon_alias = alias; - else if (alias->d_parent == dentry->d_parent && - alias->d_name.hash == dentry->d_name.hash && - alias->d_name.len == dentry->d_name.len && - memcmp(alias->d_name.name, dentry->d_name.name, - dentry->d_name.len) == 0) - invalid_alias = alias; - spin_unlock(&alias->d_lock); - - if (invalid_alias) - break; - } - alias = invalid_alias ?: discon_alias ?: NULL; - if (alias) { + if (alias->d_parent != dentry->d_parent) + continue; + if (alias->d_name.hash != dentry->d_name.hash) + continue; + if (alias->d_name.len != dentry->d_name.len || + memcmp(alias->d_name.name, dentry->d_name.name, + dentry->d_name.len) != 0) + continue; spin_lock(&alias->d_lock); dget_dlock(alias); spin_unlock(&alias->d_lock); + spin_unlock(&inode->i_lock); + return alias; } spin_unlock(&inode->i_lock); - return alias; + return NULL; } /* @@ -434,7 +427,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry) */ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) { - if (inode) { + if (inode && !S_ISDIR(inode->i_mode)) { struct dentry *new = ll_find_alias(inode, de); if (new) { @@ -445,8 +438,13 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) new, d_inode(new), d_count(new), new->d_flags); return new; } + d_add(de, inode); + } else { + struct dentry *new = d_splice_alias(inode, de); + + if (new) + de = new; } - d_add(de, inode); CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n", de, d_inode(de), d_count(de), de->d_flags); return de; diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 90c7324575e4..155ce3cf6f60 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -267,7 +267,7 @@ sa_kill(struct ll_statahead_info *sai, struct sa_entry *entry) /* called by scanner after use, sa_entry will be killed */ static void -sa_put(struct ll_statahead_info *sai, struct sa_entry *entry) +sa_put(struct ll_statahead_info *sai, struct sa_entry *entry, struct ll_inode_info *lli) { struct sa_entry *tmp, *next; @@ -295,7 +295,11 @@ sa_put(struct ll_statahead_info *sai, struct sa_entry *entry) sa_kill(sai, tmp); } - wake_up(&sai->sai_thread.t_ctl_waitq); + spin_lock(&lli->lli_sa_lock); + if (sai->sai_task) + wake_up_process(sai->sai_task); + spin_unlock(&lli->lli_sa_lock); + } /* @@ -383,7 +387,7 @@ static void ll_agl_add(struct ll_statahead_info *sai, } if (added > 0) - wake_up(&sai->sai_agl_thread.t_ctl_waitq); + wake_up_process(sai->sai_agl_task); } /* allocate sai */ @@ -403,8 +407,6 @@ static struct ll_statahead_info *ll_sai_alloc(struct dentry *dentry) sai->sai_max = LL_SA_RPC_MIN; sai->sai_index = 1; init_waitqueue_head(&sai->sai_waitq); - init_waitqueue_head(&sai->sai_thread.t_ctl_waitq); - init_waitqueue_head(&sai->sai_agl_thread.t_ctl_waitq); INIT_LIST_HEAD(&sai->sai_interim_entries); INIT_LIST_HEAD(&sai->sai_entries); @@ -466,8 +468,8 @@ static void ll_sai_put(struct ll_statahead_info *sai) lli->lli_sai = NULL; spin_unlock(&lli->lli_sa_lock); - LASSERT(thread_is_stopped(&sai->sai_thread)); - LASSERT(thread_is_stopped(&sai->sai_agl_thread)); + LASSERT(sai->sai_task == NULL); + LASSERT(sai->sai_agl_task == NULL); LASSERT(sai->sai_sent == sai->sai_replied); LASSERT(!sa_has_callback(sai)); @@ -647,7 +649,6 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, struct ll_inode_info *lli = ll_i2info(dir); struct ll_statahead_info *sai = lli->lli_sai; struct sa_entry *entry = (struct sa_entry *)minfo->mi_cbdata; - wait_queue_head_t *waitq = NULL; __u64 handle = 0; if (it_disposition(it, DISP_LOOKUP_NEG)) @@ -658,7 +659,6 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, * sai should be always valid, no need to refcount */ LASSERT(sai); - LASSERT(!thread_is_stopped(&sai->sai_thread)); LASSERT(entry); CDEBUG(D_READA, "sa_entry %.*s rc %d\n", @@ -682,8 +682,9 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, spin_lock(&lli->lli_sa_lock); if (rc) { if (__sa_make_ready(sai, entry, rc)) - waitq = &sai->sai_waitq; + wake_up(&sai->sai_waitq); } else { + int first = 0; entry->se_minfo = minfo; entry->se_req = ptlrpc_request_addref(req); /* @@ -694,14 +695,15 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, */ entry->se_handle = handle; if (!sa_has_callback(sai)) - waitq = &sai->sai_thread.t_ctl_waitq; + first = 1; list_add_tail(&entry->se_list, &sai->sai_interim_entries); + + if (first && sai->sai_task) + wake_up_process(sai->sai_task); } sai->sai_replied++; - if (waitq) - wake_up(waitq); spin_unlock(&lli->lli_sa_lock); return rc; @@ -861,37 +863,13 @@ static int ll_agl_thread(void *arg) struct inode *dir = d_inode(parent); struct ll_inode_info *plli = ll_i2info(dir); struct ll_inode_info *clli; - struct ll_sb_info *sbi = ll_i2sbi(dir); - struct ll_statahead_info *sai; - struct ptlrpc_thread *thread; - struct l_wait_info lwi = { 0 }; + /* We already own this reference, so it is safe to take it without a lock. */ + struct ll_statahead_info *sai = plli->lli_sai; - sai = ll_sai_get(dir); - thread = &sai->sai_agl_thread; - thread->t_pid = current_pid(); CDEBUG(D_READA, "agl thread started: sai %p, parent %pd\n", sai, parent); - atomic_inc(&sbi->ll_agl_total); - spin_lock(&plli->lli_agl_lock); - sai->sai_agl_valid = 1; - if (thread_is_init(thread)) - /* If someone else has changed the thread state - * (e.g. already changed to SVC_STOPPING), we can't just - * blindly overwrite that setting. - */ - thread_set_flags(thread, SVC_RUNNING); - spin_unlock(&plli->lli_agl_lock); - wake_up(&thread->t_ctl_waitq); - - while (1) { - l_wait_event(thread->t_ctl_waitq, - !list_empty(&sai->sai_agls) || - !thread_is_running(thread), - &lwi); - - if (!thread_is_running(thread)) - break; + while (!kthread_should_stop()) { spin_lock(&plli->lli_agl_lock); /* The statahead thread maybe help to process AGL entries, @@ -906,6 +884,12 @@ static int ll_agl_thread(void *arg) } else { spin_unlock(&plli->lli_agl_lock); } + + set_current_state(TASK_IDLE); + if (list_empty(&sai->sai_agls) && + !kthread_should_stop()) + schedule(); + __set_current_state(TASK_RUNNING); } spin_lock(&plli->lli_agl_lock); @@ -919,20 +903,16 @@ static int ll_agl_thread(void *arg) iput(&clli->lli_vfs_inode); spin_lock(&plli->lli_agl_lock); } - thread_set_flags(thread, SVC_STOPPED); spin_unlock(&plli->lli_agl_lock); - wake_up(&thread->t_ctl_waitq); - ll_sai_put(sai); CDEBUG(D_READA, "agl thread stopped: sai %p, parent %pd\n", sai, parent); + ll_sai_put(sai); return 0; } /* start agl thread */ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai) { - struct ptlrpc_thread *thread = &sai->sai_agl_thread; - struct l_wait_info lwi = { 0 }; struct ll_inode_info *plli; struct task_struct *task; @@ -940,17 +920,22 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai) sai, parent); plli = ll_i2info(d_inode(parent)); - task = kthread_run(ll_agl_thread, parent, "ll_agl_%u", - plli->lli_opendir_pid); + task = kthread_create(ll_agl_thread, parent, "ll_agl_%u", + plli->lli_opendir_pid); if (IS_ERR(task)) { CERROR("can't start ll_agl thread, rc: %ld\n", PTR_ERR(task)); - thread_set_flags(thread, SVC_STOPPED); return; } - l_wait_event(thread->t_ctl_waitq, - thread_is_running(thread) || thread_is_stopped(thread), - &lwi); + sai->sai_agl_task = task; + atomic_inc(&ll_i2sbi(d_inode(parent))->ll_agl_total); + spin_lock(&plli->lli_agl_lock); + sai->sai_agl_valid = 1; + spin_unlock(&plli->lli_agl_lock); + /* Get an extra reference that the thread holds */ + ll_sai_get(d_inode(parent)); + + wake_up_process(task); } /* statahead thread main function */ @@ -960,20 +945,13 @@ static int ll_statahead_thread(void *arg) struct inode *dir = d_inode(parent); struct ll_inode_info *lli = ll_i2info(dir); struct ll_sb_info *sbi = ll_i2sbi(dir); - struct ll_statahead_info *sai; - struct ptlrpc_thread *sa_thread; - struct ptlrpc_thread *agl_thread; + struct ll_statahead_info *sai = lli->lli_sai; struct page *page = NULL; __u64 pos = 0; int first = 0; int rc = 0; struct md_op_data *op_data; - struct l_wait_info lwi = { 0 }; - sai = ll_sai_get(dir); - sa_thread = &sai->sai_thread; - agl_thread = &sai->sai_agl_thread; - sa_thread->t_pid = current_pid(); CDEBUG(D_READA, "statahead thread starting: sai %p, parent %pd\n", sai, parent); @@ -986,21 +964,7 @@ static int ll_statahead_thread(void *arg) op_data->op_max_pages = ll_i2sbi(dir)->ll_md_brw_pages; - if (sbi->ll_flags & LL_SBI_AGL_ENABLED) - ll_start_agl(parent, sai); - - atomic_inc(&sbi->ll_sa_total); - spin_lock(&lli->lli_sa_lock); - if (thread_is_init(sa_thread)) - /* If someone else has changed the thread state - * (e.g. already changed to SVC_STOPPING), we can't just - * blindly overwrite that setting. - */ - thread_set_flags(sa_thread, SVC_RUNNING); - spin_unlock(&lli->lli_sa_lock); - wake_up(&sa_thread->t_ctl_waitq); - - while (pos != MDS_DIR_END_OFF && thread_is_running(sa_thread)) { + while (pos != MDS_DIR_END_OFF && sai->sai_task) { struct lu_dirpage *dp; struct lu_dirent *ent; @@ -1017,7 +981,7 @@ static int ll_statahead_thread(void *arg) dp = page_address(page); for (ent = lu_dirent_start(dp); - ent && thread_is_running(sa_thread) && !sa_low_hit(sai); + ent && sai->sai_task && !sa_low_hit(sai); ent = lu_dirent_next(ent)) { struct lu_fid fid; __u64 hash; @@ -1067,14 +1031,7 @@ static int ll_statahead_thread(void *arg) fid_le_to_cpu(&fid, &ent->lde_fid); - /* wait for spare statahead window */ do { - l_wait_event(sa_thread->t_ctl_waitq, - !sa_sent_full(sai) || - sa_has_callback(sai) || - !list_empty(&sai->sai_agls) || - !thread_is_running(sa_thread), - &lwi); sa_handle_callback(sai); spin_lock(&lli->lli_agl_lock); @@ -1094,8 +1051,16 @@ static int ll_statahead_thread(void *arg) spin_lock(&lli->lli_agl_lock); } spin_unlock(&lli->lli_agl_lock); - } while (sa_sent_full(sai) && - thread_is_running(sa_thread)); + + set_current_state(TASK_IDLE); + if (sa_sent_full(sai) && + !sa_has_callback(sai) && + agl_list_empty(sai) && + sai->sai_task) + /* wait for spare statahead window */ + schedule(); + __set_current_state(TASK_RUNNING); + } while (sa_sent_full(sai) && sai->sai_task); sa_statahead(parent, name, namelen, &fid); } @@ -1118,7 +1083,7 @@ static int ll_statahead_thread(void *arg) if (rc < 0) { spin_lock(&lli->lli_sa_lock); - thread_set_flags(sa_thread, SVC_STOPPING); + sai->sai_task = NULL; lli->lli_sa_enabled = 0; spin_unlock(&lli->lli_sa_lock); } @@ -1127,59 +1092,46 @@ static int ll_statahead_thread(void *arg) * statahead is finished, but statahead entries need to be cached, wait * for file release to stop me. */ - while (thread_is_running(sa_thread)) { - l_wait_event(sa_thread->t_ctl_waitq, - sa_has_callback(sai) || - !agl_list_empty(sai) || - !thread_is_running(sa_thread), - &lwi); - + while (sai->sai_task) { sa_handle_callback(sai); + + set_current_state(TASK_IDLE); + if (!sa_has_callback(sai) && + sai->sai_task) + schedule(); + __set_current_state(TASK_RUNNING); } out: - if (sai->sai_agl_valid) { - spin_lock(&lli->lli_agl_lock); - thread_set_flags(agl_thread, SVC_STOPPING); - spin_unlock(&lli->lli_agl_lock); - wake_up(&agl_thread->t_ctl_waitq); + if (sai->sai_agl_task) { + kthread_stop(sai->sai_agl_task); CDEBUG(D_READA, "stop agl thread: sai %p pid %u\n", - sai, (unsigned int)agl_thread->t_pid); - l_wait_event(agl_thread->t_ctl_waitq, - thread_is_stopped(agl_thread), - &lwi); - } else { - /* Set agl_thread flags anyway. */ - thread_set_flags(agl_thread, SVC_STOPPED); + sai, (unsigned int)sai->sai_agl_task->pid); + sai->sai_agl_task = NULL; } - /* * wait for inflight statahead RPCs to finish, and then we can free sai * safely because statahead RPC will access sai data */ while (sai->sai_sent != sai->sai_replied) { /* in case we're not woken up, timeout wait */ - lwi = LWI_TIMEOUT(msecs_to_jiffies(MSEC_PER_SEC >> 3), - NULL, NULL); - l_wait_event(sa_thread->t_ctl_waitq, - sai->sai_sent == sai->sai_replied, &lwi); + schedule_timeout_idle(HZ>>3); } /* release resources held by statahead RPCs */ sa_handle_callback(sai); - spin_lock(&lli->lli_sa_lock); - thread_set_flags(sa_thread, SVC_STOPPED); - spin_unlock(&lli->lli_sa_lock); - CDEBUG(D_READA, "statahead thread stopped: sai %p, parent %pd\n", sai, parent); + spin_lock(&lli->lli_sa_lock); + sai->sai_task = NULL; + spin_unlock(&lli->lli_sa_lock); + wake_up(&sai->sai_waitq); - wake_up(&sa_thread->t_ctl_waitq); ll_sai_put(sai); - return rc; + do_exit(rc); } /* authorize opened dir handle @key to statahead */ @@ -1221,13 +1173,13 @@ void ll_deauthorize_statahead(struct inode *dir, void *key) lli->lli_opendir_pid = 0; lli->lli_sa_enabled = 0; sai = lli->lli_sai; - if (sai && thread_is_running(&sai->sai_thread)) { + if (sai && sai->sai_task) { /* * statahead thread may not quit yet because it needs to cache * entries, now it's time to tell it to quit. */ - thread_set_flags(&sai->sai_thread, SVC_STOPPING); - wake_up(&sai->sai_thread.t_ctl_waitq); + wake_up_process(sai->sai_task); + sai->sai_task = NULL; } spin_unlock(&lli->lli_sa_lock); } @@ -1382,7 +1334,6 @@ static int revalidate_statahead_dentry(struct inode *dir, { struct ll_inode_info *lli = ll_i2info(dir); struct sa_entry *entry = NULL; - struct l_wait_info lwi = { 0 }; struct ll_dentry_data *ldd; int rc = 0; @@ -1432,10 +1383,8 @@ static int revalidate_statahead_dentry(struct inode *dir, spin_lock(&lli->lli_sa_lock); sai->sai_index_wait = entry->se_index; spin_unlock(&lli->lli_sa_lock); - lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(30), NULL, - LWI_ON_SIGNAL_NOOP, NULL); - rc = l_wait_event(sai->sai_waitq, sa_ready(entry), &lwi); - if (rc < 0) { + if (0 == wait_event_idle_timeout(sai->sai_waitq, + sa_ready(entry), 30 * HZ)) { /* * entry may not be ready, so it may be used by inflight * statahead RPC, don't free it. @@ -1500,7 +1449,7 @@ out_unplug: */ ldd = ll_d2d(*dentryp); ldd->lld_sa_generation = lli->lli_sa_generation; - sa_put(sai, entry); + sa_put(sai, entry, lli); return rc; } @@ -1520,8 +1469,6 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry) { struct ll_inode_info *lli = ll_i2info(dir); struct ll_statahead_info *sai = NULL; - struct l_wait_info lwi = { 0 }; - struct ptlrpc_thread *thread; struct task_struct *task; struct dentry *parent = dentry->d_parent; int rc; @@ -1561,19 +1508,21 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry) CDEBUG(D_READA, "start statahead thread: [pid %d] [parent %pd]\n", current_pid(), parent); - task = kthread_run(ll_statahead_thread, parent, "ll_sa_%u", - lli->lli_opendir_pid); - thread = &sai->sai_thread; + task = kthread_create(ll_statahead_thread, parent, "ll_sa_%u", + lli->lli_opendir_pid); if (IS_ERR(task)) { rc = PTR_ERR(task); CERROR("can't start ll_sa thread, rc : %d\n", rc); goto out; } - l_wait_event(thread->t_ctl_waitq, - thread_is_running(thread) || thread_is_stopped(thread), - &lwi); - ll_sai_put(sai); + if (ll_i2sbi(parent->d_inode)->ll_flags & LL_SBI_AGL_ENABLED) + ll_start_agl(parent, sai); + + atomic_inc(&ll_i2sbi(parent->d_inode)->ll_sa_total); + sai->sai_task = task; + + wake_up_process(task); /* * We don't stat-ahead for the first dirent since we are already in diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c index 9b0bb3541a84..861e7a60f408 100644 --- a/drivers/staging/lustre/lustre/llite/super25.c +++ b/drivers/staging/lustre/lustre/llite/super25.c @@ -85,8 +85,7 @@ MODULE_ALIAS_FS("lustre"); static int __init lustre_init(void) { - struct lnet_process_id lnet_id; - int i, rc; + int rc; BUILD_BUG_ON(sizeof(LUSTRE_VOLATILE_HDR) != LUSTRE_VOLATILE_HDR_LEN + 1); @@ -125,20 +124,6 @@ static int __init lustre_init(void) goto out_debugfs; } - /* Nodes with small feet have little entropy. The NID for this - * node gives the most entropy in the low bits - */ - for (i = 0;; i++) { - u32 seed; - - if (LNetGetId(i, &lnet_id) == -ENOENT) - break; - if (LNET_NETTYP(LNET_NIDNET(lnet_id.nid)) != LOLND) { - seed = LNET_NIDADDR(lnet_id.nid); - add_device_randomness(&seed, sizeof(seed)); - } - } - rc = vvp_global_init(); if (rc != 0) goto out_sysfs; diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c index 532384c91447..2d78432963dc 100644 --- a/drivers/staging/lustre/lustre/llite/xattr.c +++ b/drivers/staging/lustre/lustre/llite/xattr.c @@ -75,7 +75,7 @@ static int xattr_type_filter(struct ll_sb_info *sbi, return -EOPNOTSUPP; if (handler->flags == XATTR_TRUSTED_T && - !capable(CFS_CAP_SYS_ADMIN)) + !capable(CAP_SYS_ADMIN)) return -EPERM; return 0; @@ -87,10 +87,10 @@ ll_xattr_set_common(const struct xattr_handler *handler, const char *name, const void *value, size_t size, int flags) { - char fullname[strlen(handler->prefix) + strlen(name) + 1]; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *req = NULL; const char *pv = value; + char *fullname; __u64 valid; int rc; @@ -141,10 +141,13 @@ ll_xattr_set_common(const struct xattr_handler *handler, return -EPERM; } - sprintf(fullname, "%s%s\n", handler->prefix, name); + fullname = kasprintf(GFP_KERNEL, "%s%s\n", handler->prefix, name); + if (!fullname) + return -ENOMEM; rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode), valid, fullname, pv, size, 0, flags, ll_i2suppgid(inode), &req); + kfree(fullname); if (rc) { if (rc == -EOPNOTSUPP && handler->flags == XATTR_USER_T) { LCONSOLE_INFO("Disabling user_xattr feature because it is not supported on the server\n"); @@ -364,11 +367,11 @@ static int ll_xattr_get_common(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *buffer, size_t size) { - char fullname[strlen(handler->prefix) + strlen(name) + 1]; struct ll_sb_info *sbi = ll_i2sbi(inode); #ifdef CONFIG_FS_POSIX_ACL struct ll_inode_info *lli = ll_i2info(inode); #endif + char *fullname; int rc; CDEBUG(D_VFSTRACE, "VFS Op:inode=" DFID "(%p)\n", @@ -411,9 +414,13 @@ static int ll_xattr_get_common(const struct xattr_handler *handler, if (handler->flags == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode)) return -ENODATA; #endif - sprintf(fullname, "%s%s\n", handler->prefix, name); - return ll_xattr_list(inode, fullname, handler->flags, buffer, size, - OBD_MD_FLXATTR); + fullname = kasprintf(GFP_KERNEL, "%s%s\n", handler->prefix, name); + if (!fullname) + return -ENOMEM; + rc = ll_xattr_list(inode, fullname, handler->flags, buffer, size, + OBD_MD_FLXATTR); + kfree(fullname); + return rc; } static ssize_t ll_getxattr_lov(struct inode *inode, void *buf, size_t buf_size) diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index c2c57f65431e..e8a9b9902c37 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -1035,7 +1035,7 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp, reqlen = offsetof(typeof(*hur), hur_user_item[nr]) + hur->hur_request.hr_data_len; - req = libcfs_kvzalloc(reqlen, GFP_NOFS); + req = kvzalloc(reqlen, GFP_NOFS); if (!req) return -ENOMEM; @@ -2695,7 +2695,7 @@ static int lmv_unpackmd(struct obd_export *exp, struct lmv_stripe_md **lsmp, if (lsm && !lmm) { int i; - for (i = 1; i < lsm->lsm_md_stripe_count; i++) { + for (i = 0; i < lsm->lsm_md_stripe_count; i++) { /* * For migrating inode, the master stripe and master * object will be the same, so do not need iput, see @@ -2733,7 +2733,7 @@ static int lmv_unpackmd(struct obd_export *exp, struct lmv_stripe_md **lsmp, lsm_size = lmv_stripe_md_size(0); if (!lsm) { - lsm = libcfs_kvzalloc(lsm_size, GFP_NOFS); + lsm = kvzalloc(lsm_size, GFP_NOFS); if (!lsm) return -ENOMEM; allocated = true; diff --git a/drivers/staging/lustre/lustre/lov/lov_ea.c b/drivers/staging/lustre/lustre/lov/lov_ea.c index d563dd73343a..c56a971745e8 100644 --- a/drivers/staging/lustre/lustre/lov/lov_ea.c +++ b/drivers/staging/lustre/lustre/lov/lov_ea.c @@ -89,7 +89,7 @@ struct lov_stripe_md *lsm_alloc_plain(u16 stripe_count) oinfo_ptrs_size = sizeof(struct lov_oinfo *) * stripe_count; lsm_size = sizeof(*lsm) + oinfo_ptrs_size; - lsm = libcfs_kvzalloc(lsm_size, GFP_NOFS); + lsm = kvzalloc(lsm_size, GFP_NOFS); if (!lsm) return NULL; diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c index c5f5d1b106dc..b823f8a21856 100644 --- a/drivers/staging/lustre/lustre/lov/lov_io.c +++ b/drivers/staging/lustre/lustre/lov/lov_io.c @@ -243,7 +243,7 @@ static int lov_io_subio_init(const struct lu_env *env, struct lov_io *lio, * when writing a page. -jay */ lio->lis_subs = - libcfs_kvzalloc(lsm->lsm_stripe_count * + kvzalloc(lsm->lsm_stripe_count * sizeof(lio->lis_subs[0]), GFP_NOFS); if (lio->lis_subs) { @@ -483,7 +483,7 @@ lov_io_data_version_end(const struct lu_env *env, const struct cl_io_slice *ios) struct lov_io_sub *sub; list_for_each_entry(sub, &lio->lis_active, sub_linkage) { - lov_io_end_wrapper(env, sub->sub_io); + lov_io_end_wrapper(sub->sub_env, sub->sub_io); parent->u.ci_data_version.dv_data_version += sub->sub_io->u.ci_data_version.dv_data_version; diff --git a/drivers/staging/lustre/lustre/lov/lov_lock.c b/drivers/staging/lustre/lustre/lov/lov_lock.c index 2fcdeb707ff9..b0292100bf26 100644 --- a/drivers/staging/lustre/lustre/lov/lov_lock.c +++ b/drivers/staging/lustre/lustre/lov/lov_lock.c @@ -145,7 +145,7 @@ static struct lov_lock *lov_lock_sub_init(const struct lu_env *env, nr++; } LASSERT(nr > 0); - lovlck = libcfs_kvzalloc(offsetof(struct lov_lock, lls_sub[nr]), + lovlck = kvzalloc(offsetof(struct lov_lock, lls_sub[nr]), GFP_NOFS); if (!lovlck) return ERR_PTR(-ENOMEM); diff --git a/drivers/staging/lustre/lustre/lov/lov_object.c b/drivers/staging/lustre/lustre/lov/lov_object.c index 897cf2cd4a24..f7c69680cb7d 100644 --- a/drivers/staging/lustre/lustre/lov/lov_object.c +++ b/drivers/staging/lustre/lustre/lov/lov_object.c @@ -242,7 +242,7 @@ static int lov_init_raid0(const struct lu_env *env, struct lov_device *dev, r0->lo_nr = lsm->lsm_stripe_count; LASSERT(r0->lo_nr <= lov_targets_nr(dev)); - r0->lo_sub = libcfs_kvzalloc(r0->lo_nr * sizeof(r0->lo_sub[0]), + r0->lo_sub = kvzalloc(r0->lo_nr * sizeof(r0->lo_sub[0]), GFP_NOFS); if (r0->lo_sub) { int psz = 0; @@ -723,15 +723,13 @@ static void lov_conf_unlock(struct lov_object *lov) static int lov_layout_wait(const struct lu_env *env, struct lov_object *lov) { - struct l_wait_info lwi = { 0 }; - while (atomic_read(&lov->lo_active_ios) > 0) { CDEBUG(D_INODE, "file:" DFID " wait for active IO, now: %d.\n", PFID(lu_object_fid(lov2lu(lov))), atomic_read(&lov->lo_active_ios)); - l_wait_event(lov->lo_waitq, - atomic_read(&lov->lo_active_ios) == 0, &lwi); + wait_event_idle(lov->lo_waitq, + atomic_read(&lov->lo_active_ios) == 0); } return 0; } @@ -1175,7 +1173,8 @@ static int fiemap_for_stripe(const struct lu_env *env, struct cl_object *obj, /* If this is a continuation FIEMAP call and we are on * starting stripe then lun_start needs to be set to - * end_offset */ + * end_offset + */ if (fs->fs_end_offset != 0 && stripeno == fs->fs_start_stripe) lun_start = fs->fs_end_offset; @@ -1200,7 +1199,8 @@ static int fiemap_for_stripe(const struct lu_env *env, struct cl_object *obj, if (IS_ERR(subobj)) return PTR_ERR(subobj); /* If the output buffer is very large and the objects have many - * extents we may need to loop on a single OST repeatedly */ + * extents we may need to loop on a single OST repeatedly + */ do { if (fiemap->fm_extent_count > 0) { /* Don't get too many extents. */ @@ -1250,7 +1250,8 @@ inactive_tgt: ost_done = true; fs->fs_device_done = true; /* If last stripe has hold at the end, - * we need to return */ + * we need to return + */ if (stripeno == fs->fs_last_stripe) { fiemap->fm_mapped_extents = 0; fs->fs_finish = true; @@ -1284,7 +1285,8 @@ inactive_tgt: } /* Clear the EXTENT_LAST flag which can be present on - * the last extent */ + * the last extent + */ if (fm_ext[ext_count - 1].fe_flags & FIEMAP_EXTENT_LAST) fm_ext[ext_count - 1].fe_flags &= ~FIEMAP_EXTENT_LAST; if (lov_stripe_size(lsm, fm_ext[ext_count - 1].fe_logical + @@ -1377,7 +1379,7 @@ static int lov_object_fiemap(const struct lu_env *env, struct cl_object *obj, if (fiemap_count_to_size(fiemap->fm_extent_count) < buffer_size) buffer_size = fiemap_count_to_size(fiemap->fm_extent_count); - fm_local = libcfs_kvzalloc(buffer_size, GFP_NOFS); + fm_local = kvzalloc(buffer_size, GFP_NOFS); if (!fm_local) { rc = -ENOMEM; goto out; diff --git a/drivers/staging/lustre/lustre/lov/lov_pack.c b/drivers/staging/lustre/lustre/lov/lov_pack.c index e5b11c4085a9..b1060d02a164 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pack.c +++ b/drivers/staging/lustre/lustre/lov/lov_pack.c @@ -333,7 +333,7 @@ int lov_getstripe(struct lov_object *obj, struct lov_stripe_md *lsm, lmmk_size = lov_mds_md_size(stripe_count, lsm->lsm_magic); - lmmk = libcfs_kvzalloc(lmmk_size, GFP_NOFS); + lmmk = kvzalloc(lmmk_size, GFP_NOFS); if (!lmmk) { rc = -ENOMEM; goto out; diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c index cfa1d7f92b0f..051450d67524 100644 --- a/drivers/staging/lustre/lustre/lov/lov_request.c +++ b/drivers/staging/lustre/lustre/lov/lov_request.c @@ -99,8 +99,7 @@ static int lov_check_set(struct lov_obd *lov, int idx) */ static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx) { - wait_queue_head_t waitq; - struct l_wait_info lwi; + int cnt = 0; struct lov_tgt_desc *tgt; int rc = 0; @@ -125,11 +124,10 @@ static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx) mutex_unlock(&lov->lov_lock); - init_waitqueue_head(&waitq); - lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(obd_timeout), - cfs_time_seconds(1), NULL, NULL); - - rc = l_wait_event(waitq, lov_check_set(lov, ost_idx), &lwi); + while (cnt < obd_timeout && !lov_check_set(lov, ost_idx)) { + schedule_timeout_uninterruptible(HZ); + cnt++; + } if (tgt->ltd_active) return 1; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 3114907ac5ff..695ef44532cf 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -660,7 +660,7 @@ static int mdc_finish_enqueue(struct obd_export *exp, LDLM_DEBUG(lock, "layout lock returned by: %s, lvb_len: %d", ldlm_it2str(it->it_op), lvb_len); - lmm = libcfs_kvzalloc(lvb_len, GFP_NOFS); + lmm = kvzalloc(lvb_len, GFP_NOFS); if (!lmm) { LDLM_LOCK_PUT(lock); return -ENOMEM; diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 03e55bca4ada..3b1c8e5a3053 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -838,7 +838,6 @@ static int mdc_getpage(struct obd_export *exp, const struct lu_fid *fid, struct ptlrpc_bulk_desc *desc; struct ptlrpc_request *req; wait_queue_head_t waitq; - struct l_wait_info lwi; int resends = 0; int rc; int i; @@ -888,9 +887,7 @@ restart_bulk: exp->exp_obd->obd_name, -EIO); return -EIO; } - lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(resends), NULL, NULL, - NULL); - l_wait_event(waitq, 0, &lwi); + wait_event_idle_timeout(waitq, 0, resends * HZ); goto restart_bulk; } @@ -1058,13 +1055,14 @@ static void mdc_adjust_dirpages(struct page **pages, int cfs_pgs, int lu_pgs) __u64 hash_end = le64_to_cpu(dp->ldp_hash_end); __u32 flags = le32_to_cpu(dp->ldp_flags); struct lu_dirpage *first = dp; - struct lu_dirent *end_dirent = NULL; - struct lu_dirent *ent; while (--lu_pgs > 0) { - ent = lu_dirent_start(dp); - for (end_dirent = ent; ent; - end_dirent = ent, ent = lu_dirent_next(ent)); + struct lu_dirent *end_dirent = NULL; + struct lu_dirent *ent; + + for (ent = lu_dirent_start(dp); ent; + ent = lu_dirent_next(ent)) + end_dirent = ent; /* Advance dp to next lu_dirpage. */ dp = (struct lu_dirpage *)((char *)dp + LU_PAGE_SIZE); diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index 79ff85feab64..c61cd23a96df 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -535,7 +535,6 @@ static int mgc_requeue_thread(void *data) spin_lock(&config_list_lock); rq_state |= RQ_RUNNING; while (!(rq_state & RQ_STOP)) { - struct l_wait_info lwi; struct config_llog_data *cld, *cld_prev; int rand = prandom_u32_max(MGC_TIMEOUT_RAND_CENTISEC); int to; @@ -556,9 +555,9 @@ static int mgc_requeue_thread(void *data) to = msecs_to_jiffies(MGC_TIMEOUT_MIN_SECONDS * MSEC_PER_SEC); /* rand is centi-seconds */ to += msecs_to_jiffies(rand * MSEC_PER_SEC / 100); - lwi = LWI_TIMEOUT(to, NULL, NULL); - l_wait_event(rq_waitq, rq_state & (RQ_STOP | RQ_PRECLEANUP), - &lwi); + wait_event_idle_timeout(rq_waitq, + rq_state & (RQ_STOP | RQ_PRECLEANUP), + to); /* * iterate & processing through the list. for each cld, process @@ -601,9 +600,7 @@ static int mgc_requeue_thread(void *data) config_log_put(cld_prev); /* Wait a bit to see if anyone else needs a requeue */ - lwi = (struct l_wait_info) { 0 }; - l_wait_event(rq_waitq, rq_state & (RQ_NOW | RQ_STOP), - &lwi); + wait_event_idle(rq_waitq, rq_state & (RQ_NOW | RQ_STOP)); spin_lock(&config_list_lock); } @@ -1630,9 +1627,7 @@ restart: if (rcl == -ESHUTDOWN && atomic_read(&mgc->u.cli.cl_mgc_refcount) > 0 && !retry) { - int secs = cfs_time_seconds(obd_timeout); struct obd_import *imp; - struct l_wait_info lwi; mutex_unlock(&cld->cld_lock); imp = class_exp2cliimp(mgc->u.cli.cl_mgc_mgsexp); @@ -1647,9 +1642,9 @@ restart: */ ptlrpc_pinger_force(imp); - lwi = LWI_TIMEOUT(secs, NULL, NULL); - l_wait_event(imp->imp_recovery_waitq, - !mgc_import_in_recovery(imp), &lwi); + wait_event_idle_timeout(imp->imp_recovery_waitq, + !mgc_import_in_recovery(imp), + obd_timeout * HZ); if (imp->imp_state == LUSTRE_IMP_FULL) { retry = true; diff --git a/drivers/staging/lustre/lustre/obdclass/cl_io.c b/drivers/staging/lustre/lustre/obdclass/cl_io.c index 6ec5218a18c1..ab84e011b560 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_io.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_io.c @@ -1097,23 +1097,24 @@ EXPORT_SYMBOL(cl_sync_io_init); int cl_sync_io_wait(const struct lu_env *env, struct cl_sync_io *anchor, long timeout) { - struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(timeout), - NULL, NULL, NULL); - int rc; + int rc = 1; LASSERT(timeout >= 0); - rc = l_wait_event(anchor->csi_waitq, - atomic_read(&anchor->csi_sync_nr) == 0, - &lwi); - if (rc < 0) { + if (timeout == 0) + wait_event_idle(anchor->csi_waitq, + atomic_read(&anchor->csi_sync_nr) == 0); + else + rc = wait_event_idle_timeout(anchor->csi_waitq, + atomic_read(&anchor->csi_sync_nr) == 0, + timeout * HZ); + if (rc == 0) { + rc = -ETIMEDOUT; CERROR("IO failed: %d, still wait for %d remaining entries\n", rc, atomic_read(&anchor->csi_sync_nr)); - lwi = (struct l_wait_info) { 0 }; - (void)l_wait_event(anchor->csi_waitq, - atomic_read(&anchor->csi_sync_nr) == 0, - &lwi); + wait_event_idle(anchor->csi_waitq, + atomic_read(&anchor->csi_sync_nr) == 0); } else { rc = anchor->csi_sync_rc; } diff --git a/drivers/staging/lustre/lustre/obdclass/cl_lock.c b/drivers/staging/lustre/lustre/obdclass/cl_lock.c index 3b683b774fef..9ca29a26a38b 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_lock.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_lock.c @@ -224,7 +224,7 @@ EXPORT_SYMBOL(cl_lock_release); const char *cl_lock_mode_name(const enum cl_lock_mode mode) { - static const char *names[] = { + static const char * const names[] = { [CLM_READ] = "R", [CLM_WRITE] = "W", [CLM_GROUP] = "G" diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c index 7b18d775b001..7809f6ae1809 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_object.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c @@ -495,7 +495,7 @@ static struct cache_stats cl_env_stats = { int cl_site_stats_print(const struct cl_site *site, struct seq_file *m) { size_t i; - static const char *pstate[] = { + static const char * const pstate[] = { [CPS_CACHED] = "c", [CPS_OWNED] = "o", [CPS_PAGEOUT] = "w", diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index b1d6ba4a3190..63ccbabb4c5a 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -48,10 +48,7 @@ struct kmem_cache *obdo_cachep; EXPORT_SYMBOL(obdo_cachep); static struct kmem_cache *import_cachep; -static struct list_head obd_zombie_imports; -static struct list_head obd_zombie_exports; -static spinlock_t obd_zombie_impexp_lock; -static void obd_zombie_impexp_notify(void); +static struct workqueue_struct *zombie_wq; static void obd_zombie_export_add(struct obd_export *exp); static void obd_zombie_import_add(struct obd_import *imp); @@ -701,6 +698,13 @@ void class_export_put(struct obd_export *exp) } EXPORT_SYMBOL(class_export_put); +static void obd_zombie_exp_cull(struct work_struct *ws) +{ + struct obd_export *export = container_of(ws, struct obd_export, exp_zombie_work); + + class_export_destroy(export); +} + /* Creates a new export, adds it to the hash table, and returns a * pointer to it. The refcount is 2: one for the hash reference, and * one for the pointer returned by this function. @@ -741,6 +745,7 @@ struct obd_export *class_new_export(struct obd_device *obd, INIT_HLIST_NODE(&export->exp_uuid_hash); spin_lock_init(&export->exp_bl_list_lock); INIT_LIST_HEAD(&export->exp_bl_list); + INIT_WORK(&export->exp_zombie_work, obd_zombie_exp_cull); export->exp_sp_peer = LUSTRE_SP_ANY; export->exp_flvr.sf_rpc = SPTLRPC_FLVR_INVALID; @@ -862,7 +867,6 @@ EXPORT_SYMBOL(class_import_get); void class_import_put(struct obd_import *imp) { - LASSERT(list_empty(&imp->imp_zombie_chain)); LASSERT_ATOMIC_GT_LT(&imp->imp_refcount, 0, LI_POISON); CDEBUG(D_INFO, "import %p refcount=%d obd=%s\n", imp, @@ -894,6 +898,13 @@ static void init_imp_at(struct imp_at *at) } } +static void obd_zombie_imp_cull(struct work_struct *ws) +{ + struct obd_import *import = container_of(ws, struct obd_import, imp_zombie_work); + + class_import_destroy(import); +} + struct obd_import *class_new_import(struct obd_device *obd) { struct obd_import *imp; @@ -903,7 +914,6 @@ struct obd_import *class_new_import(struct obd_device *obd) return NULL; INIT_LIST_HEAD(&imp->imp_pinger_chain); - INIT_LIST_HEAD(&imp->imp_zombie_chain); INIT_LIST_HEAD(&imp->imp_replay_list); INIT_LIST_HEAD(&imp->imp_sending_list); INIT_LIST_HEAD(&imp->imp_delayed_list); @@ -917,6 +927,7 @@ struct obd_import *class_new_import(struct obd_device *obd) imp->imp_obd = class_incref(obd, "import", imp); mutex_init(&imp->imp_sec_mutex); init_waitqueue_head(&imp->imp_recovery_waitq); + INIT_WORK(&imp->imp_zombie_work, obd_zombie_imp_cull); atomic_set(&imp->imp_refcount, 2); atomic_set(&imp->imp_unregistering, 0); @@ -1098,81 +1109,6 @@ EXPORT_SYMBOL(class_fail_export); void (*class_export_dump_hook)(struct obd_export *) = NULL; #endif -/* Total amount of zombies to be destroyed */ -static int zombies_count; - -/** - * kill zombie imports and exports - */ -static void obd_zombie_impexp_cull(void) -{ - struct obd_import *import; - struct obd_export *export; - - do { - spin_lock(&obd_zombie_impexp_lock); - - import = NULL; - if (!list_empty(&obd_zombie_imports)) { - import = list_entry(obd_zombie_imports.next, - struct obd_import, - imp_zombie_chain); - list_del_init(&import->imp_zombie_chain); - } - - export = NULL; - if (!list_empty(&obd_zombie_exports)) { - export = list_entry(obd_zombie_exports.next, - struct obd_export, - exp_obd_chain); - list_del_init(&export->exp_obd_chain); - } - - spin_unlock(&obd_zombie_impexp_lock); - - if (import) { - class_import_destroy(import); - spin_lock(&obd_zombie_impexp_lock); - zombies_count--; - spin_unlock(&obd_zombie_impexp_lock); - } - - if (export) { - class_export_destroy(export); - spin_lock(&obd_zombie_impexp_lock); - zombies_count--; - spin_unlock(&obd_zombie_impexp_lock); - } - - cond_resched(); - } while (import || export); -} - -static struct completion obd_zombie_start; -static struct completion obd_zombie_stop; -static unsigned long obd_zombie_flags; -static wait_queue_head_t obd_zombie_waitq; -static pid_t obd_zombie_pid; - -enum { - OBD_ZOMBIE_STOP = 0x0001, -}; - -/** - * check for work for kill zombie import/export thread. - */ -static int obd_zombie_impexp_check(void *arg) -{ - int rc; - - spin_lock(&obd_zombie_impexp_lock); - rc = (zombies_count == 0) && - !test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags); - spin_unlock(&obd_zombie_impexp_lock); - - return rc; -} - /** * Add export to the obd_zombie thread and notify it. */ @@ -1182,12 +1118,7 @@ static void obd_zombie_export_add(struct obd_export *exp) LASSERT(!list_empty(&exp->exp_obd_chain)); list_del_init(&exp->exp_obd_chain); spin_unlock(&exp->exp_obd->obd_dev_lock); - spin_lock(&obd_zombie_impexp_lock); - zombies_count++; - list_add(&exp->exp_obd_chain, &obd_zombie_exports); - spin_unlock(&obd_zombie_impexp_lock); - - obd_zombie_impexp_notify(); + queue_work(zombie_wq, &exp->exp_zombie_work); } /** @@ -1196,40 +1127,7 @@ static void obd_zombie_export_add(struct obd_export *exp) static void obd_zombie_import_add(struct obd_import *imp) { LASSERT(!imp->imp_sec); - spin_lock(&obd_zombie_impexp_lock); - LASSERT(list_empty(&imp->imp_zombie_chain)); - zombies_count++; - list_add(&imp->imp_zombie_chain, &obd_zombie_imports); - spin_unlock(&obd_zombie_impexp_lock); - - obd_zombie_impexp_notify(); -} - -/** - * notify import/export destroy thread about new zombie. - */ -static void obd_zombie_impexp_notify(void) -{ - /* - * Make sure obd_zombie_impexp_thread get this notification. - * It is possible this signal only get by obd_zombie_barrier, and - * barrier gulps this notification and sleeps away and hangs ensues - */ - wake_up_all(&obd_zombie_waitq); -} - -/** - * check whether obd_zombie is idle - */ -static int obd_zombie_is_idle(void) -{ - int rc; - - LASSERT(!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags)); - spin_lock(&obd_zombie_impexp_lock); - rc = (zombies_count == 0); - spin_unlock(&obd_zombie_impexp_lock); - return rc; + queue_work(zombie_wq, &imp->imp_zombie_work); } /** @@ -1237,64 +1135,19 @@ static int obd_zombie_is_idle(void) */ void obd_zombie_barrier(void) { - struct l_wait_info lwi = { 0 }; - - if (obd_zombie_pid == current_pid()) - /* don't wait for myself */ - return; - l_wait_event(obd_zombie_waitq, obd_zombie_is_idle(), &lwi); + flush_workqueue(zombie_wq); } EXPORT_SYMBOL(obd_zombie_barrier); /** - * destroy zombie export/import thread. - */ -static int obd_zombie_impexp_thread(void *unused) -{ - unshare_fs_struct(); - complete(&obd_zombie_start); - - obd_zombie_pid = current_pid(); - - while (!test_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags)) { - struct l_wait_info lwi = { 0 }; - - l_wait_event(obd_zombie_waitq, - !obd_zombie_impexp_check(NULL), &lwi); - obd_zombie_impexp_cull(); - - /* - * Notify obd_zombie_barrier callers that queues - * may be empty. - */ - wake_up(&obd_zombie_waitq); - } - - complete(&obd_zombie_stop); - - return 0; -} - -/** * start destroy zombie import/export thread */ int obd_zombie_impexp_init(void) { - struct task_struct *task; - - INIT_LIST_HEAD(&obd_zombie_imports); - INIT_LIST_HEAD(&obd_zombie_exports); - spin_lock_init(&obd_zombie_impexp_lock); - init_completion(&obd_zombie_start); - init_completion(&obd_zombie_stop); - init_waitqueue_head(&obd_zombie_waitq); - obd_zombie_pid = 0; - - task = kthread_run(obd_zombie_impexp_thread, NULL, "obd_zombid"); - if (IS_ERR(task)) - return PTR_ERR(task); + zombie_wq = alloc_workqueue("obd_zombid", 0, 0); + if (!zombie_wq) + return -ENOMEM; - wait_for_completion(&obd_zombie_start); return 0; } @@ -1303,9 +1156,7 @@ int obd_zombie_impexp_init(void) */ void obd_zombie_impexp_stop(void) { - set_bit(OBD_ZOMBIE_STOP, &obd_zombie_flags); - obd_zombie_impexp_notify(); - wait_for_completion(&obd_zombie_stop); + destroy_workqueue(zombie_wq); } struct obd_request_slot_waiter { @@ -1336,7 +1187,6 @@ static bool obd_request_slot_avail(struct client_obd *cli, int obd_get_request_slot(struct client_obd *cli) { struct obd_request_slot_waiter orsw; - struct l_wait_info lwi; int rc; spin_lock(&cli->cl_loi_list_lock); @@ -1351,11 +1201,9 @@ int obd_get_request_slot(struct client_obd *cli) orsw.orsw_signaled = false; spin_unlock(&cli->cl_loi_list_lock); - lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); - rc = l_wait_event(orsw.orsw_waitq, - obd_request_slot_avail(cli, &orsw) || - orsw.orsw_signaled, - &lwi); + rc = l_wait_event_abortable(orsw.orsw_waitq, + obd_request_slot_avail(cli, &orsw) || + orsw.orsw_signaled); /* * Here, we must take the lock to avoid the on-stack 'orsw' to be @@ -1593,7 +1441,6 @@ static inline bool obd_mod_rpc_slot_avail(struct client_obd *cli, u16 obd_get_mod_rpc_slot(struct client_obd *cli, __u32 opc, struct lookup_intent *it) { - struct l_wait_info lwi = LWI_INTR(NULL, NULL); bool close_req = false; u16 i, max; @@ -1631,8 +1478,8 @@ u16 obd_get_mod_rpc_slot(struct client_obd *cli, __u32 opc, CDEBUG(D_RPCTRACE, "%s: sleeping for a modify RPC slot opc %u, max %hu\n", cli->cl_import->imp_obd->obd_name, opc, max); - l_wait_event(cli->cl_mod_rpcs_waitq, - obd_mod_rpc_slot_avail(cli, close_req), &lwi); + wait_event_idle(cli->cl_mod_rpcs_waitq, + obd_mod_rpc_slot_avail(cli, close_req)); } while (true); } EXPORT_SYMBOL(obd_get_mod_rpc_slot); diff --git a/drivers/staging/lustre/lustre/obdclass/linkea.c b/drivers/staging/lustre/lustre/obdclass/linkea.c index fe1638b0916e..74c99ee216bb 100644 --- a/drivers/staging/lustre/lustre/obdclass/linkea.c +++ b/drivers/staging/lustre/lustre/obdclass/linkea.c @@ -33,9 +33,11 @@ int linkea_data_new(struct linkea_data *ldata, struct lu_buf *buf) { - ldata->ld_buf = lu_buf_check_and_alloc(buf, PAGE_SIZE); - if (!ldata->ld_buf->lb_buf) + buf->lb_buf = kzalloc(PAGE_SIZE, GFP_NOFS); + if (!buf->lb_buf) return -ENOMEM; + buf->lb_len = PAGE_SIZE; + ldata->ld_buf = buf; ldata->ld_leh = ldata->ld_buf->lb_buf; ldata->ld_leh->leh_magic = LINK_EA_MAGIC; ldata->ld_leh->leh_len = sizeof(struct link_ea_header); @@ -158,11 +160,15 @@ int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname, } if (leh->leh_len + reclen > ldata->ld_buf->lb_len) { - if (lu_buf_check_and_grow(ldata->ld_buf, - leh->leh_len + reclen) < 0) + /* Note: this never happens as MAX_LINKEA_SIZE is 4096, while + * the initial allocation is PAGE_SIZE. + */ + void *b = krealloc(ldata->ld_buf->lb_buf, leh->leh_len + reclen, GFP_NOFS); + if (!b) return -ENOMEM; - leh = ldata->ld_leh = ldata->ld_buf->lb_buf; + ldata->ld_buf->lb_len = leh->leh_len + reclen; + leh = ldata->ld_leh = ldata->ld_buf->lb_buf = b; } ldata->ld_lee = ldata->ld_buf->lb_buf + leh->leh_len; diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c index 57951237def2..7bceee7f121e 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c @@ -180,7 +180,7 @@ int obd_ioctl_getdata(char **buf, int *len, void __user *arg) * obdfilter-survey is an example, which relies on ioctl. So we'd * better avoid vmalloc on ioctl path. LU-66 */ - *buf = libcfs_kvzalloc(hdr.ioc_len, GFP_NOFS); + *buf = kvzalloc(hdr.ioc_len, GFP_KERNEL); if (!*buf) { CERROR("Cannot allocate control buffer of len %d\n", hdr.ioc_len); @@ -251,7 +251,7 @@ static long obd_class_ioctl(struct file *filp, unsigned int cmd, int err = 0; /* Allow non-root access for OBD_IOC_PING_TARGET - used by lfs check */ - if (!capable(CFS_CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET)) + if (!capable(CAP_SYS_ADMIN) && (cmd != OBD_IOC_PING_TARGET)) return err = -EACCES; if ((cmd & 0xffffff00) == ((int)'T') << 8) /* ignore all tty ioctls */ return err = -ENOTTY; diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c index cd051e31233e..693e1129f1f9 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ b/drivers/staging/lustre/lustre/obdclass/llog.c @@ -155,7 +155,7 @@ int llog_init_handle(const struct lu_env *env, struct llog_handle *handle, LASSERT(!handle->lgh_hdr); LASSERT(chunk_size >= LLOG_MIN_CHUNK_SIZE); - llh = libcfs_kvzalloc(sizeof(*llh), GFP_NOFS); + llh = kvzalloc(sizeof(*llh), GFP_KERNEL); if (!llh) return -ENOMEM; handle->lgh_hdr = llh; @@ -240,7 +240,7 @@ static int llog_process_thread(void *arg) /* expect chunk_size to be power of two */ LASSERT(is_power_of_2(chunk_size)); - buf = libcfs_kvzalloc(chunk_size, GFP_NOFS); + buf = kvzalloc(chunk_size, GFP_NOFS); if (!buf) { lpi->lpi_rc = -ENOMEM; return 0; @@ -466,7 +466,7 @@ int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_handle **lgh, struct llog_logid *logid, char *name, enum llog_open_param open_param) { - int raised; + const struct cred *old_cred = NULL; int rc; LASSERT(ctxt); @@ -483,12 +483,18 @@ int llog_open(const struct lu_env *env, struct llog_ctxt *ctxt, (*lgh)->lgh_ctxt = ctxt; (*lgh)->lgh_logops = ctxt->loc_logops; - raised = cfs_cap_raised(CFS_CAP_SYS_RESOURCE); - if (!raised) - cfs_cap_raise(CFS_CAP_SYS_RESOURCE); + if (cap_raised(current_cap(), CAP_SYS_RESOURCE)) { + struct cred *cred = prepare_creds(); + + if (cred) { + cap_raise(cred->cap_effective, CAP_SYS_RESOURCE); + old_cred = override_creds(cred); + } + } rc = ctxt->loc_logops->lop_open(env, *lgh, logid, name, open_param); - if (!raised) - cfs_cap_lower(CFS_CAP_SYS_RESOURCE); + if (old_cred) + revert_creds(old_cred); + if (rc) { llog_free_handle(*lgh); *lgh = NULL; diff --git a/drivers/staging/lustre/lustre/obdclass/llog_obd.c b/drivers/staging/lustre/lustre/obdclass/llog_obd.c index 28bbaa2136ac..26aea114a29b 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/llog_obd.c @@ -104,7 +104,6 @@ EXPORT_SYMBOL(__llog_ctxt_put); int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt) { - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); struct obd_llog_group *olg; int rc, idx; @@ -129,8 +128,8 @@ int llog_cleanup(const struct lu_env *env, struct llog_ctxt *ctxt) CERROR("Error %d while cleaning up ctxt %p\n", rc, ctxt); - l_wait_event(olg->olg_waitq, - llog_group_ctxt_null(olg, idx), &lwi); + l_wait_event_abortable(olg->olg_waitq, + llog_group_ctxt_null(olg, idx)); return rc; } diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index e1f4ef2bddd4..2ed350527398 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -1467,7 +1467,7 @@ int lprocfs_write_frac_u64_helper(const char __user *buffer, { char kernbuf[22], *end, *pbuf; __u64 whole, frac = 0, units; - unsigned frac_d = 1; + unsigned int frac_d = 1; int sign = 1; if (count > (sizeof(kernbuf) - 1)) @@ -1585,7 +1585,7 @@ int ldebugfs_seq_create(struct dentry *parent, const char *name, struct dentry *entry; /* Disallow secretly (un)writable entries. */ - LASSERT((seq_fops->write == NULL) == ((mode & 0222) == 0)); + LASSERT((!seq_fops->write) == ((mode & 0222) == 0)); entry = debugfs_create_file(name, mode, parent, data, seq_fops); if (IS_ERR_OR_NULL(entry)) diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index 2719abbff85f..3ae16e8501c2 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -1380,12 +1380,8 @@ static void key_fini(struct lu_context *ctx, int index) lu_ref_del(&key->lct_reference, "ctx", ctx); atomic_dec(&key->lct_used); - if ((ctx->lc_tags & LCT_NOREF) == 0) { -#ifdef CONFIG_MODULE_UNLOAD - LINVRNT(module_refcount(key->lct_owner) > 0); -#endif + if ((ctx->lc_tags & LCT_NOREF) == 0) module_put(key->lct_owner); - } ctx->lc_value[index] = NULL; } } @@ -1411,7 +1407,7 @@ void lu_context_key_degister(struct lu_context_key *key) while (atomic_read(&key->lct_used) > 1) { spin_unlock(&lu_keys_guard); CDEBUG(D_INFO, "%s: \"%s\" %p, %d\n", - __func__, key->lct_owner ? key->lct_owner->name : "", + __func__, module_name(key->lct_owner), key, atomic_read(&key->lct_used)); schedule(); spin_lock(&lu_keys_guard); @@ -1551,7 +1547,7 @@ void lu_context_key_quiesce(struct lu_context_key *key) spin_unlock(&lu_keys_guard); CDEBUG(D_INFO, "%s: \"%s\" %p, %d (%d)\n", __func__, - key->lct_owner ? key->lct_owner->name : "", + module_name(key->lct_owner), key, atomic_read(&key->lct_used), atomic_read(&lu_key_initing_cnt)); schedule(); @@ -1619,7 +1615,6 @@ static int keys_fill(struct lu_context *ctx) LINVRNT(key->lct_init); LINVRNT(key->lct_index == i); - LASSERT(key->lct_owner); if (!(ctx->lc_tags & LCT_NOREF) && !try_module_get(key->lct_owner)) { /* module is unloading, skip this key */ @@ -1797,10 +1792,10 @@ int lu_env_refill(struct lu_env *env) EXPORT_SYMBOL(lu_env_refill); struct lu_site_stats { - unsigned lss_populated; - unsigned lss_max_search; - unsigned lss_total; - unsigned lss_busy; + unsigned int lss_populated; + unsigned int lss_max_search; + unsigned int lss_total; + unsigned int lss_busy; }; static void lu_site_stats_get(struct cfs_hash *hs, @@ -2061,73 +2056,3 @@ void lu_kmem_fini(struct lu_kmem_descr *caches) } } EXPORT_SYMBOL(lu_kmem_fini); - -void lu_buf_free(struct lu_buf *buf) -{ - LASSERT(buf); - if (buf->lb_buf) { - LASSERT(buf->lb_len > 0); - kvfree(buf->lb_buf); - buf->lb_buf = NULL; - buf->lb_len = 0; - } -} -EXPORT_SYMBOL(lu_buf_free); - -void lu_buf_alloc(struct lu_buf *buf, size_t size) -{ - LASSERT(buf); - LASSERT(!buf->lb_buf); - LASSERT(!buf->lb_len); - buf->lb_buf = libcfs_kvzalloc(size, GFP_NOFS); - if (likely(buf->lb_buf)) - buf->lb_len = size; -} -EXPORT_SYMBOL(lu_buf_alloc); - -void lu_buf_realloc(struct lu_buf *buf, size_t size) -{ - lu_buf_free(buf); - lu_buf_alloc(buf, size); -} -EXPORT_SYMBOL(lu_buf_realloc); - -struct lu_buf *lu_buf_check_and_alloc(struct lu_buf *buf, size_t len) -{ - if (!buf->lb_buf && !buf->lb_len) - lu_buf_alloc(buf, len); - - if ((len > buf->lb_len) && buf->lb_buf) - lu_buf_realloc(buf, len); - - return buf; -} -EXPORT_SYMBOL(lu_buf_check_and_alloc); - -/** - * Increase the size of the \a buf. - * preserves old data in buffer - * old buffer remains unchanged on error - * \retval 0 or -ENOMEM - */ -int lu_buf_check_and_grow(struct lu_buf *buf, size_t len) -{ - char *ptr; - - if (len <= buf->lb_len) - return 0; - - ptr = libcfs_kvzalloc(len, GFP_NOFS); - if (!ptr) - return -ENOMEM; - - /* Free the old buf */ - if (buf->lb_buf) { - memcpy(ptr, buf->lb_buf, buf->lb_len); - kvfree(buf->lb_buf); - } - - buf->lb_buf = ptr; - buf->lb_len = len; - return 0; -} diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c index 2d6da2431a09..f53b1a3c342e 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_handles.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_handles.c @@ -184,8 +184,8 @@ int class_handle_init(void) LASSERT(!handle_hash); - handle_hash = libcfs_kvzalloc(sizeof(*bucket) * HANDLE_HASH_SIZE, - GFP_NOFS); + handle_hash = kvzalloc(sizeof(*bucket) * HANDLE_HASH_SIZE, + GFP_KERNEL); if (!handle_hash) return -ENOMEM; diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index 997c0f9aafb5..277576b586db 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -455,7 +455,7 @@ static int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg) spin_unlock(&obd->obd_dev_lock); while (obd->obd_conn_inprogress > 0) - yield(); + cond_resched(); smp_rmb(); if (lcfg->lcfg_bufcount >= 2 && LUSTRE_CFG_BUFLEN(lcfg, 1) > 0) { diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index acc1ea773c9c..f5e8214ac37b 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -243,7 +243,7 @@ int lustre_start_mgc(struct super_block *sb) libcfs_nid2str_r(nid, nidstr, sizeof(nidstr)); mgcname = kasprintf(GFP_NOFS, "%s%s", LUSTRE_MGC_OBDNAME, nidstr); - niduuid = kasprintf(GFP_NOFS, "%s_%x", mgcname, i); + niduuid = kasprintf(GFP_NOFS, "%s_%x", mgcname, 0); if (!mgcname || !niduuid) { rc = -ENOMEM; goto out_free; diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index b9c1dc7e61b0..99a76db51ae0 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -752,7 +752,7 @@ static struct lu_device *echo_device_free(const struct lu_env *env, spin_unlock(&ec->ec_lock); CERROR("echo_client still has objects at cleanup time, wait for 1 second\n"); set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(1)); + schedule_timeout(HZ); lu_site_purge(env, ed->ed_site, -1); spin_lock(&ec->ec_lock); } @@ -1502,7 +1502,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len, switch (cmd) { case OBD_IOC_CREATE: /* may create echo object */ - if (!capable(CFS_CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { rc = -EPERM; goto out; } @@ -1511,7 +1511,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len, goto out; case OBD_IOC_DESTROY: - if (!capable(CFS_CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { rc = -EPERM; goto out; } @@ -1534,7 +1534,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len, goto out; case OBD_IOC_SETATTR: - if (!capable(CFS_CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { rc = -EPERM; goto out; } @@ -1547,7 +1547,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len, goto out; case OBD_IOC_BRW_WRITE: - if (!capable(CFS_CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN)) { rc = -EPERM; goto out; } diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 5767ac2a7d16..459503727ce3 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -934,8 +934,6 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext, enum osc_extent_state state) { struct osc_object *obj = ext->oe_obj; - struct l_wait_info lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(600), NULL, - LWI_ON_SIGNAL_NOOP, NULL); int rc = 0; osc_object_lock(obj); @@ -958,18 +956,19 @@ static int osc_extent_wait(const struct lu_env *env, struct osc_extent *ext, osc_extent_release(env, ext); /* wait for the extent until its state becomes @state */ - rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state), &lwi); - if (rc == -ETIMEDOUT) { + rc = wait_event_idle_timeout(ext->oe_waitq, + extent_wait_cb(ext, state), 600 * HZ); + if (rc == 0) { OSC_EXTENT_DUMP(D_ERROR, ext, "%s: wait ext to %u timedout, recovery in progress?\n", cli_name(osc_cli(obj)), state); - lwi = LWI_INTR(NULL, NULL); - rc = l_wait_event(ext->oe_waitq, extent_wait_cb(ext, state), - &lwi); + wait_event_idle(ext->oe_waitq, extent_wait_cb(ext, state)); } - if (rc == 0 && ext->oe_rc < 0) + if (ext->oe_rc < 0) rc = ext->oe_rc; + else + rc = 0; return rc; } @@ -1530,7 +1529,7 @@ static int osc_enter_cache_try(struct client_obd *cli, if (rc < 0) return 0; - if (cli->cl_dirty_pages <= cli->cl_dirty_max_pages && + if (cli->cl_dirty_pages < cli->cl_dirty_max_pages && atomic_long_read(&obd_dirty_pages) + 1 <= obd_max_dirty_pages) { osc_consume_write_grant(cli, &oap->oap_brw_page); if (transient) { @@ -1569,12 +1568,9 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli, struct osc_object *osc = oap->oap_obj; struct lov_oinfo *loi = osc->oo_oinfo; struct osc_cache_waiter ocw; - struct l_wait_info lwi; + unsigned long timeout = (AT_OFF ? obd_timeout : at_max) * HZ; int rc = -EDQUOT; - lwi = LWI_TIMEOUT_INTR(cfs_time_seconds(AT_OFF ? obd_timeout : at_max), - NULL, LWI_ON_SIGNAL_NOOP, NULL); - OSC_DUMP_GRANT(D_CACHE, cli, "need:%d\n", bytes); spin_lock(&cli->cl_loi_list_lock); @@ -1617,13 +1613,15 @@ static int osc_enter_cache(const struct lu_env *env, struct client_obd *cli, CDEBUG(D_CACHE, "%s: sleeping for cache space @ %p for %p\n", cli_name(cli), &ocw, oap); - rc = l_wait_event(ocw.ocw_waitq, ocw_granted(cli, &ocw), &lwi); + rc = wait_event_idle_timeout(ocw.ocw_waitq, + ocw_granted(cli, &ocw), timeout); spin_lock(&cli->cl_loi_list_lock); - if (rc < 0) { - /* l_wait_event is interrupted by signal, or timed out */ + if (rc == 0) { + /* wait_event is interrupted by signal, or timed out */ list_del_init(&ocw.ocw_entry); + rc = -ETIMEDOUT; break; } LASSERT(list_empty(&ocw.ocw_entry)); @@ -2347,7 +2345,7 @@ int osc_prep_async_page(struct osc_object *osc, struct osc_page *ops, oap->oap_obj_off = offset; LASSERT(!(offset & ~PAGE_MASK)); - if (capable(CFS_CAP_SYS_RESOURCE)) + if (capable(CAP_SYS_RESOURCE)) oap->oap_brw_flags = OBD_BRW_NOQUOTA; INIT_LIST_HEAD(&oap->oap_pending_item); @@ -2386,7 +2384,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io, /* Set the OBD_BRW_SRVLOCK before the page is queued. */ brw_flags |= ops->ops_srvlock ? OBD_BRW_SRVLOCK : 0; - if (capable(CFS_CAP_SYS_RESOURCE)) { + if (capable(CAP_SYS_RESOURCE)) { brw_flags |= OBD_BRW_NOQUOTA; cmd |= OBD_BRW_NOQUOTA; } diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c index f82c87a77550..6baa8e2e00c9 100644 --- a/drivers/staging/lustre/lustre/osc/osc_object.c +++ b/drivers/staging/lustre/lustre/osc/osc_object.c @@ -328,7 +328,7 @@ int osc_object_is_contended(struct osc_object *obj) * ll_file_is_contended. */ retry_time = cfs_time_add(obj->oo_contention_time, - cfs_time_seconds(osc_contention_time)); + osc_contention_time * HZ); if (cfs_time_after(cur_time, retry_time)) { osc_object_clear_contended(obj); return 0; @@ -454,12 +454,10 @@ struct lu_object *osc_object_alloc(const struct lu_env *env, int osc_object_invalidate(const struct lu_env *env, struct osc_object *osc) { - struct l_wait_info lwi = { 0 }; - CDEBUG(D_INODE, "Invalidate osc object: %p, # of active IOs: %d\n", osc, atomic_read(&osc->oo_nr_ios)); - l_wait_event(osc->oo_io_waitq, !atomic_read(&osc->oo_nr_ios), &lwi); + wait_event_idle(osc->oo_io_waitq, !atomic_read(&osc->oo_nr_ios)); /* Discard all dirty pages of this object. */ osc_cache_truncate_start(env, osc, 0, NULL); diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index 20094b6309f9..01a930dbbf64 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -307,7 +307,7 @@ void osc_page_submit(const struct lu_env *env, struct osc_page *opg, oap->oap_count = opg->ops_to - opg->ops_from; oap->oap_brw_flags = brw_flags | OBD_BRW_SYNC; - if (capable(CFS_CAP_SYS_RESOURCE)) { + if (capable(CAP_SYS_RESOURCE)) { oap->oap_brw_flags |= OBD_BRW_NOQUOTA; oap->oap_cmd |= OBD_BRW_NOQUOTA; } @@ -759,7 +759,6 @@ out: static int osc_lru_alloc(const struct lu_env *env, struct client_obd *cli, struct osc_page *opg) { - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); struct osc_io *oio = osc_env_io(env); int rc = 0; @@ -782,9 +781,8 @@ static int osc_lru_alloc(const struct lu_env *env, struct client_obd *cli, cond_resched(); - rc = l_wait_event(osc_lru_waitq, - atomic_long_read(cli->cl_lru_left) > 0, - &lwi); + rc = l_wait_event_abortable(osc_lru_waitq, + atomic_long_read(cli->cl_lru_left) > 0); if (rc < 0) break; diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 45b1ebf33363..1c2bbbf5d864 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -552,14 +552,12 @@ static int osc_destroy(const struct lu_env *env, struct obd_export *exp, req->rq_interpret_reply = osc_destroy_interpret; if (!osc_can_send_destroy(cli)) { - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); - /* * Wait until the number of on-going destroy RPCs drops * under max_rpc_in_flight */ - l_wait_event_exclusive(cli->cl_destroy_waitq, - osc_can_send_destroy(cli), &lwi); + l_wait_event_abortable_exclusive(cli->cl_destroy_waitq, + osc_can_send_destroy(cli)); } /* Do not wait for response */ @@ -933,7 +931,7 @@ static u32 osc_checksum_bulk(int nob, u32 pg_count, { __u32 cksum; int i = 0; - struct cfs_crypto_hash_desc *hdesc; + struct ahash_request *hdesc; unsigned int bufsize; unsigned char cfs_alg = cksum_obd2cfs(cksum_type); diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index bac4b2304bad..ca096fadb9c0 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -504,19 +504,16 @@ void ptlrpc_request_cache_free(struct ptlrpc_request *req) */ void ptlrpc_free_rq_pool(struct ptlrpc_request_pool *pool) { - struct list_head *l, *tmp; struct ptlrpc_request *req; - spin_lock(&pool->prp_lock); - list_for_each_safe(l, tmp, &pool->prp_req_list) { - req = list_entry(l, struct ptlrpc_request, rq_list); + while ((req = list_first_entry_or_null(&pool->prp_req_list, + struct ptlrpc_request, rq_list))) { list_del(&req->rq_list); LASSERT(req->rq_reqbuf); LASSERT(req->rq_reqbuf_len == pool->prp_rq_size); kvfree(req->rq_reqbuf); ptlrpc_request_cache_free(req); } - spin_unlock(&pool->prp_lock); kfree(pool); } EXPORT_SYMBOL(ptlrpc_free_rq_pool); @@ -544,10 +541,10 @@ int ptlrpc_add_rqs_to_pool(struct ptlrpc_request_pool *pool, int num_rq) struct lustre_msg *msg; spin_unlock(&pool->prp_lock); - req = ptlrpc_request_cache_alloc(GFP_NOFS); + req = ptlrpc_request_cache_alloc(GFP_KERNEL); if (!req) return i; - msg = libcfs_kvzalloc(size, GFP_NOFS); + msg = kvzalloc(size, GFP_KERNEL); if (!msg) { ptlrpc_request_cache_free(req); return i; @@ -656,16 +653,13 @@ static void __ptlrpc_free_req_to_pool(struct ptlrpc_request *request) void ptlrpc_add_unreplied(struct ptlrpc_request *req) { struct obd_import *imp = req->rq_import; - struct list_head *tmp; struct ptlrpc_request *iter; assert_spin_locked(&imp->imp_lock); LASSERT(list_empty(&req->rq_unreplied_list)); /* unreplied list is sorted by xid in ascending order */ - list_for_each_prev(tmp, &imp->imp_unreplied_list) { - iter = list_entry(tmp, struct ptlrpc_request, - rq_unreplied_list); + list_for_each_entry_reverse(iter, &imp->imp_unreplied_list, rq_unreplied_list) { LASSERT(req->rq_xid != iter->rq_xid); if (req->rq_xid < iter->rq_xid) @@ -766,7 +760,7 @@ int ptlrpc_request_bufs_pack(struct ptlrpc_request *request, * fail_loc */ set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(2)); + schedule_timeout(2 * HZ); set_current_state(TASK_RUNNING); } } @@ -1001,18 +995,14 @@ struct ptlrpc_request_set *ptlrpc_prep_fcset(int max, set_producer_func func, */ void ptlrpc_set_destroy(struct ptlrpc_request_set *set) { - struct list_head *tmp; - struct list_head *next; + struct ptlrpc_request *req; int expected_phase; int n = 0; /* Requests on the set should either all be completed, or all be new */ expected_phase = (atomic_read(&set->set_remaining) == 0) ? RQ_PHASE_COMPLETE : RQ_PHASE_NEW; - list_for_each(tmp, &set->set_requests) { - struct ptlrpc_request *req = - list_entry(tmp, struct ptlrpc_request, rq_set_chain); - + list_for_each_entry(req, &set->set_requests, rq_set_chain) { LASSERT(req->rq_phase == expected_phase); n++; } @@ -1021,9 +1011,9 @@ void ptlrpc_set_destroy(struct ptlrpc_request_set *set) atomic_read(&set->set_remaining) == n, "%d / %d\n", atomic_read(&set->set_remaining), n); - list_for_each_safe(tmp, next, &set->set_requests) { - struct ptlrpc_request *req = - list_entry(tmp, struct ptlrpc_request, rq_set_chain); + while ((req = list_first_entry_or_null(&set->set_requests, + struct ptlrpc_request, + rq_set_chain))) { list_del_init(&req->rq_set_chain); LASSERT(req->rq_phase == expected_phase); @@ -1588,7 +1578,8 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req) spin_lock(&imp->imp_lock); if (!list_empty(&req->rq_list)) { list_del_init(&req->rq_list); - atomic_dec(&req->rq_import->imp_inflight); + if (atomic_dec_and_test(&req->rq_import->imp_inflight)) + wake_up_all(&req->rq_import->imp_recovery_waitq); } spin_unlock(&imp->imp_lock); ptlrpc_rqphase_move(req, RQ_PHASE_NEW); @@ -1639,7 +1630,7 @@ static inline int ptlrpc_set_producer(struct ptlrpc_request_set *set) */ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set) { - struct list_head *tmp, *next; + struct ptlrpc_request *req, *next; struct list_head comp_reqs; int force_timer_recalc = 0; @@ -1647,9 +1638,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set) return 1; INIT_LIST_HEAD(&comp_reqs); - list_for_each_safe(tmp, next, &set->set_requests) { - struct ptlrpc_request *req = - list_entry(tmp, struct ptlrpc_request, rq_set_chain); + list_for_each_entry_safe(req, next, &set->set_requests, rq_set_chain) { struct obd_import *imp = req->rq_import; int unregistered = 0; int rc = 0; @@ -1773,7 +1762,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set) } /* - * ptlrpc_set_wait->l_wait_event sets lwi_allow_intr + * ptlrpc_set_wait allow signal to abort the timeout * so it sets rq_intr regardless of individual rpc * timeouts. The synchronous IO waiting path sets * rq_intr irrespective of whether ptlrpcd @@ -2121,19 +2110,15 @@ int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink) /** * Time out all uncompleted requests in request set pointed by \a data - * Callback used when waiting on sets with l_wait_event. - * Always returns 1. + * Called when wait_event_idle_timeout times out. */ -int ptlrpc_expired_set(void *data) +void ptlrpc_expired_set(struct ptlrpc_request_set *set) { - struct ptlrpc_request_set *set = data; - struct list_head *tmp; + struct ptlrpc_request *req; time64_t now = ktime_get_real_seconds(); /* A timeout expired. See which reqs it applies to... */ - list_for_each(tmp, &set->set_requests) { - struct ptlrpc_request *req = - list_entry(tmp, struct ptlrpc_request, rq_set_chain); + list_for_each_entry(req, &set->set_requests, rq_set_chain) { /* don't expire request waiting for context */ if (req->rq_wait_ctx) @@ -2155,13 +2140,6 @@ int ptlrpc_expired_set(void *data) */ ptlrpc_expire_one_request(req, 1); } - - /* - * When waiting for a whole set, we always break out of the - * sleep so we can recalculate the timeout, or enable interrupts - * if everyone's timed out. - */ - return 1; } /** @@ -2177,18 +2155,14 @@ EXPORT_SYMBOL(ptlrpc_mark_interrupted); /** * Interrupts (sets interrupted flag) all uncompleted requests in - * a set \a data. Callback for l_wait_event for interruptible waits. + * a set \a data. Called when l_wait_event_abortable_timeout receives signal. */ -static void ptlrpc_interrupted_set(void *data) +static void ptlrpc_interrupted_set(struct ptlrpc_request_set *set) { - struct ptlrpc_request_set *set = data; - struct list_head *tmp; - + struct ptlrpc_request *req; CDEBUG(D_RPCTRACE, "INTERRUPTED SET %p\n", set); - list_for_each(tmp, &set->set_requests) { - struct ptlrpc_request *req = - list_entry(tmp, struct ptlrpc_request, rq_set_chain); + list_for_each_entry(req, &set->set_requests, rq_set_chain) { if (req->rq_phase != RQ_PHASE_RPC && req->rq_phase != RQ_PHASE_UNREG_RPC) @@ -2203,14 +2177,12 @@ static void ptlrpc_interrupted_set(void *data) */ int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set) { - struct list_head *tmp; time64_t now = ktime_get_real_seconds(); int timeout = 0; struct ptlrpc_request *req; time64_t deadline; - list_for_each(tmp, &set->set_requests) { - req = list_entry(tmp, struct ptlrpc_request, rq_set_chain); + list_for_each_entry(req, &set->set_requests, rq_set_chain) { /* Request in-flight? */ if (!(((req->rq_phase == RQ_PHASE_RPC) && !req->rq_waiting) || @@ -2249,17 +2221,13 @@ int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set) */ int ptlrpc_set_wait(struct ptlrpc_request_set *set) { - struct list_head *tmp; struct ptlrpc_request *req; - struct l_wait_info lwi; int rc, timeout; if (set->set_producer) (void)ptlrpc_set_producer(set); else - list_for_each(tmp, &set->set_requests) { - req = list_entry(tmp, struct ptlrpc_request, - rq_set_chain); + list_for_each_entry(req, &set->set_requests, rq_set_chain) { if (req->rq_phase == RQ_PHASE_NEW) (void)ptlrpc_send_new_req(req); } @@ -2277,46 +2245,47 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set) CDEBUG(D_RPCTRACE, "set %p going to sleep for %d seconds\n", set, timeout); - if (timeout == 0 && !signal_pending(current)) + if (timeout == 0 && !signal_pending(current)) { /* * No requests are in-flight (ether timed out * or delayed), so we can allow interrupts. * We still want to block for a limited time, * so we allow interrupts during the timeout. */ - lwi = LWI_TIMEOUT_INTR_ALL(cfs_time_seconds(1), - ptlrpc_expired_set, - ptlrpc_interrupted_set, set); - else + rc = l_wait_event_abortable_timeout(set->set_waitq, + ptlrpc_check_set(NULL, set), + HZ); + if (rc == 0) { + rc = -ETIMEDOUT; + ptlrpc_expired_set(set); + } else if (rc < 0) { + rc = -EINTR; + ptlrpc_interrupted_set(set); + } else + rc = 0; + } else { /* * At least one request is in flight, so no * interrupts are allowed. Wait until all * complete, or an in-flight req times out. */ - lwi = LWI_TIMEOUT(cfs_time_seconds(timeout ? timeout : 1), - ptlrpc_expired_set, set); - - rc = l_wait_event(set->set_waitq, ptlrpc_check_set(NULL, set), &lwi); - - /* - * LU-769 - if we ignored the signal because it was already - * pending when we started, we need to handle it now or we risk - * it being ignored forever - */ - if (rc == -ETIMEDOUT && !lwi.lwi_allow_intr && - signal_pending(current)) { - sigset_t blocked_sigs = - cfs_block_sigsinv(LUSTRE_FATAL_SIGS); - - /* - * In fact we only interrupt for the "fatal" signals - * like SIGINT or SIGKILL. We still ignore less - * important signals since ptlrpc set is not easily - * reentrant from userspace again - */ - if (signal_pending(current)) - ptlrpc_interrupted_set(set); - cfs_restore_sigs(blocked_sigs); + rc = wait_event_idle_timeout(set->set_waitq, + ptlrpc_check_set(NULL, set), + (timeout ? timeout : 1) * HZ); + if (rc == 0) { + ptlrpc_expired_set(set); + rc = -ETIMEDOUT; + /* + * LU-769 - if we ignored the signal + * because it was already pending when + * we started, we need to handle it + * now or we risk it being ignored + * forever + */ + if (l_fatal_signal_pending(current)) + ptlrpc_interrupted_set(set); + } else + rc = 0; } LASSERT(rc == 0 || rc == -EINTR || rc == -ETIMEDOUT); @@ -2331,9 +2300,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set) * the error cases -eeb. */ if (rc == 0 && atomic_read(&set->set_remaining) == 0) { - list_for_each(tmp, &set->set_requests) { - req = list_entry(tmp, struct ptlrpc_request, - rq_set_chain); + list_for_each_entry(req, &set->set_requests, rq_set_chain) { spin_lock(&req->rq_lock); req->rq_invalid_rqset = 1; spin_unlock(&req->rq_lock); @@ -2344,9 +2311,7 @@ int ptlrpc_set_wait(struct ptlrpc_request_set *set) LASSERT(atomic_read(&set->set_remaining) == 0); rc = set->set_rc; /* rq_status of already freed requests if any */ - list_for_each(tmp, &set->set_requests) { - req = list_entry(tmp, struct ptlrpc_request, rq_set_chain); - + list_for_each_entry(req, &set->set_requests, rq_set_chain) { LASSERT(req->rq_phase == RQ_PHASE_COMPLETE); if (req->rq_status != 0) rc = req->rq_status; @@ -2495,7 +2460,6 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async) { int rc; wait_queue_head_t *wq; - struct l_wait_info lwi; /* Might sleep. */ LASSERT(!in_interrupt()); @@ -2524,7 +2488,7 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async) return 0; /* - * We have to l_wait_event() whatever the result, to give liblustre + * We have to wait_event_idle_timeout() whatever the result, to give liblustre * a chance to run reply_in_callback(), and to make sure we've * unlinked before returning a req to the pool. */ @@ -2538,16 +2502,17 @@ static int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async) * Network access will complete in finite time but the HUGE * timeout lets us CWARN for visibility of sluggish NALs */ - lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(LONG_UNLINK), - cfs_time_seconds(1), NULL, NULL); - rc = l_wait_event(*wq, !ptlrpc_client_recv_or_unlink(request), - &lwi); - if (rc == 0) { + int cnt = 0; + while (cnt < LONG_UNLINK && + (rc = wait_event_idle_timeout(*wq, + !ptlrpc_client_recv_or_unlink(request), + HZ)) == 0) + cnt += 1; + if (rc > 0) { ptlrpc_rqphase_move(request, request->rq_next_phase); return 1; } - LASSERT(rc == -ETIMEDOUT); DEBUG_REQ(D_WARNING, request, "Unexpectedly long timeout receiving_reply=%d req_ulinked=%d reply_unlinked=%d", request->rq_receiving_reply, @@ -2725,8 +2690,7 @@ EXPORT_SYMBOL(ptlrpc_request_addref); void ptlrpc_retain_replayable_request(struct ptlrpc_request *req, struct obd_import *imp) { - struct list_head *tmp; - + struct ptlrpc_request *iter; assert_spin_locked(&imp->imp_lock); if (req->rq_transno == 0) { @@ -2753,10 +2717,7 @@ void ptlrpc_retain_replayable_request(struct ptlrpc_request *req, LASSERT(imp->imp_replayable); /* Balanced in ptlrpc_free_committed, usually. */ ptlrpc_request_addref(req); - list_for_each_prev(tmp, &imp->imp_replay_list) { - struct ptlrpc_request *iter = - list_entry(tmp, struct ptlrpc_request, rq_replay_list); - + list_for_each_entry_reverse(iter, &imp->imp_replay_list, rq_replay_list) { /* * We may have duplicate transnos if we create and then * open a file, or for closes retained if to match creating @@ -2964,7 +2925,7 @@ int ptlrpc_replay_req(struct ptlrpc_request *req) */ void ptlrpc_abort_inflight(struct obd_import *imp) { - struct list_head *tmp, *n; + struct ptlrpc_request *req, *n; /* * Make sure that no new requests get processed for this import. @@ -2978,10 +2939,7 @@ void ptlrpc_abort_inflight(struct obd_import *imp) * locked? Also, how do we know if the requests on the list are * being freed at this time? */ - list_for_each_safe(tmp, n, &imp->imp_sending_list) { - struct ptlrpc_request *req = - list_entry(tmp, struct ptlrpc_request, rq_list); - + list_for_each_entry_safe(req, n, &imp->imp_sending_list, rq_list) { DEBUG_REQ(D_RPCTRACE, req, "inflight"); spin_lock(&req->rq_lock); @@ -2993,10 +2951,7 @@ void ptlrpc_abort_inflight(struct obd_import *imp) spin_unlock(&req->rq_lock); } - list_for_each_safe(tmp, n, &imp->imp_delayed_list) { - struct ptlrpc_request *req = - list_entry(tmp, struct ptlrpc_request, rq_list); - + list_for_each_entry_safe(req, n, &imp->imp_delayed_list, rq_list) { DEBUG_REQ(D_RPCTRACE, req, "aborting waiting req"); spin_lock(&req->rq_lock); @@ -3023,12 +2978,9 @@ void ptlrpc_abort_inflight(struct obd_import *imp) */ void ptlrpc_abort_set(struct ptlrpc_request_set *set) { - struct list_head *tmp, *pos; - - list_for_each_safe(pos, tmp, &set->set_requests) { - struct ptlrpc_request *req = - list_entry(pos, struct ptlrpc_request, rq_set_chain); + struct ptlrpc_request *req, *tmp; + list_for_each_entry_safe(req, tmp, &set->set_requests, rq_set_chain) { spin_lock(&req->rq_lock); if (req->rq_phase != RQ_PHASE_RPC) { spin_unlock(&req->rq_lock); diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index 811b7ab3a582..130bacc2c891 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -490,8 +490,6 @@ int ptlrpc_uuid_to_peer(struct obd_uuid *uuid, static void ptlrpc_ni_fini(void) { - wait_queue_head_t waitq; - struct l_wait_info lwi; int rc; int retries; @@ -515,10 +513,7 @@ static void ptlrpc_ni_fini(void) if (retries != 0) CWARN("Event queue still busy\n"); - /* Wait for a bit */ - init_waitqueue_head(&waitq); - lwi = LWI_TIMEOUT(cfs_time_seconds(2), NULL, NULL); - l_wait_event(waitq, 0, &lwi); + schedule_timeout_uninterruptible(2 * HZ); break; } } diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index 5b0f65536c29..a2c4fc3488b1 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -242,15 +242,13 @@ ptlrpc_inflight_deadline(struct ptlrpc_request *req, time64_t now) static unsigned int ptlrpc_inflight_timeout(struct obd_import *imp) { time64_t now = ktime_get_real_seconds(); - struct list_head *tmp, *n; - struct ptlrpc_request *req; + struct ptlrpc_request *req, *n; unsigned int timeout = 0; spin_lock(&imp->imp_lock); - list_for_each_safe(tmp, n, &imp->imp_sending_list) { - req = list_entry(tmp, struct ptlrpc_request, rq_list); + list_for_each_entry_safe(req, n, &imp->imp_sending_list, rq_list) timeout = max(ptlrpc_inflight_deadline(req, now), timeout); - } + spin_unlock(&imp->imp_lock); return timeout; } @@ -263,9 +261,7 @@ static unsigned int ptlrpc_inflight_timeout(struct obd_import *imp) */ void ptlrpc_invalidate_import(struct obd_import *imp) { - struct list_head *tmp, *n; - struct ptlrpc_request *req; - struct l_wait_info lwi; + struct ptlrpc_request *req, *n; unsigned int timeout; int rc; @@ -306,19 +302,15 @@ void ptlrpc_invalidate_import(struct obd_import *imp) * callbacks. Cap it at obd_timeout -- these should all * have been locally cancelled by ptlrpc_abort_inflight. */ - lwi = LWI_TIMEOUT_INTERVAL( - cfs_timeout_cap(cfs_time_seconds(timeout)), - (timeout > 1) ? cfs_time_seconds(1) : - cfs_time_seconds(1) / 2, - NULL, NULL); - rc = l_wait_event(imp->imp_recovery_waitq, - (atomic_read(&imp->imp_inflight) == 0), - &lwi); - if (rc) { + rc = wait_event_idle_timeout(imp->imp_recovery_waitq, + atomic_read(&imp->imp_inflight) == 0, + obd_timeout * HZ); + + if (rc == 0) { const char *cli_tgt = obd2cli_tgt(imp->imp_obd); - CERROR("%s: rc = %d waiting for callback (%d != 0)\n", - cli_tgt, rc, + CERROR("%s: timeout waiting for callback (%d != 0)\n", + cli_tgt, atomic_read(&imp->imp_inflight)); spin_lock(&imp->imp_lock); @@ -341,19 +333,13 @@ void ptlrpc_invalidate_import(struct obd_import *imp) */ rc = 0; } else { - list_for_each_safe(tmp, n, - &imp->imp_sending_list) { - req = list_entry(tmp, - struct ptlrpc_request, - rq_list); + list_for_each_entry_safe(req, n, + &imp->imp_sending_list, rq_list) { DEBUG_REQ(D_ERROR, req, "still on sending list"); } - list_for_each_safe(tmp, n, - &imp->imp_delayed_list) { - req = list_entry(tmp, - struct ptlrpc_request, - rq_list); + list_for_each_entry_safe(req, n, + &imp->imp_delayed_list, rq_list) { DEBUG_REQ(D_ERROR, req, "still on delayed list"); } @@ -365,7 +351,7 @@ void ptlrpc_invalidate_import(struct obd_import *imp) } spin_unlock(&imp->imp_lock); } - } while (rc != 0); + } while (rc == 0); /* * Let's additionally check that no new rpcs added to import in @@ -430,21 +416,19 @@ void ptlrpc_fail_import(struct obd_import *imp, __u32 conn_cnt) int ptlrpc_reconnect_import(struct obd_import *imp) { - struct l_wait_info lwi; - int secs = cfs_time_seconds(obd_timeout); int rc; ptlrpc_pinger_force(imp); CDEBUG(D_HA, "%s: recovery started, waiting %u seconds\n", - obd2cli_tgt(imp->imp_obd), secs); + obd2cli_tgt(imp->imp_obd), obd_timeout); - lwi = LWI_TIMEOUT(secs, NULL, NULL); - rc = l_wait_event(imp->imp_recovery_waitq, - !ptlrpc_import_in_recovery(imp), &lwi); + rc = wait_event_idle_timeout(imp->imp_recovery_waitq, + !ptlrpc_import_in_recovery(imp), + obd_timeout * HZ); CDEBUG(D_HA, "%s: recovery finished s:%s\n", obd2cli_tgt(imp->imp_obd), ptlrpc_import_state_name(imp->imp_state)); - return rc; + return rc == 0 ? -ETIMEDOUT : 0; } EXPORT_SYMBOL(ptlrpc_reconnect_import); @@ -564,14 +548,13 @@ static int import_select_connection(struct obd_import *imp) static int ptlrpc_first_transno(struct obd_import *imp, __u64 *transno) { struct ptlrpc_request *req; - struct list_head *tmp; /* The requests in committed_list always have smaller transnos than * the requests in replay_list */ if (!list_empty(&imp->imp_committed_list)) { - tmp = imp->imp_committed_list.next; - req = list_entry(tmp, struct ptlrpc_request, rq_replay_list); + req = list_first_entry(&imp->imp_committed_list, + struct ptlrpc_request, rq_replay_list); *transno = req->rq_transno; if (req->rq_transno == 0) { DEBUG_REQ(D_ERROR, req, @@ -581,8 +564,8 @@ static int ptlrpc_first_transno(struct obd_import *imp, __u64 *transno) return 1; } if (!list_empty(&imp->imp_replay_list)) { - tmp = imp->imp_replay_list.next; - req = list_entry(tmp, struct ptlrpc_request, rq_replay_list); + req = list_first_entry(&imp->imp_replay_list, + struct ptlrpc_request, rq_replay_list); *transno = req->rq_transno; if (req->rq_transno == 0) { DEBUG_REQ(D_ERROR, req, "zero transno in replay_list"); @@ -1503,25 +1486,25 @@ int ptlrpc_disconnect_import(struct obd_import *imp, int noclose) } if (ptlrpc_import_in_recovery(imp)) { - struct l_wait_info lwi; long timeout; if (AT_OFF) { if (imp->imp_server_timeout) - timeout = cfs_time_seconds(obd_timeout / 2); + timeout = obd_timeout * HZ / 2; else - timeout = cfs_time_seconds(obd_timeout); + timeout = obd_timeout * HZ; } else { int idx = import_at_get_index(imp, imp->imp_client->cli_request_portal); - timeout = cfs_time_seconds( - at_get(&imp->imp_at.iat_service_estimate[idx])); + timeout = at_get(&imp->imp_at.iat_service_estimate[idx]) * HZ; } - lwi = LWI_TIMEOUT_INTR(cfs_timeout_cap(timeout), - back_to_sleep, LWI_ON_SIGNAL_NOOP, NULL); - rc = l_wait_event(imp->imp_recovery_waitq, - !ptlrpc_import_in_recovery(imp), &lwi); + if (wait_event_idle_timeout(imp->imp_recovery_waitq, + !ptlrpc_import_in_recovery(imp), + cfs_timeout_cap(timeout)) == 0) + l_wait_event_abortable( + imp->imp_recovery_waitq, + !ptlrpc_import_in_recovery(imp)); } spin_lock(&imp->imp_lock); diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c index 18769d335751..2855f38c8190 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/layout.c +++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c @@ -1555,7 +1555,7 @@ struct req_format RQF_OST_GET_INFO_FIEMAP = EXPORT_SYMBOL(RQF_OST_GET_INFO_FIEMAP); /* Convenience macro */ -#define FMT_FIELD(fmt, i, j) (fmt)->rf_fields[(i)].d[(j)] +#define FMT_FIELD(fmt, i, j) ((fmt)->rf_fields[(i)].d[(j)]) /** * Initializes the capsule abstraction by computing and setting the \a rf_idx diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index 047d712e850c..86883abaad2c 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -229,7 +229,6 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async) { struct ptlrpc_bulk_desc *desc = req->rq_bulk; wait_queue_head_t *wq; - struct l_wait_info lwi; int rc; LASSERT(!in_interrupt()); /* might sleep */ @@ -246,7 +245,7 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async) /* the unlink ensures the callback happens ASAP and is the last * one. If it fails, it must be because completion just happened, - * but we must still l_wait_event() in this case to give liblustre + * but we must still wait_event() in this case to give liblustre * a chance to run client_bulk_callback() */ mdunlink_iterate_helper(desc->bd_mds, desc->bd_md_max_brw); @@ -270,15 +269,17 @@ int ptlrpc_unregister_bulk(struct ptlrpc_request *req, int async) /* Network access will complete in finite time but the HUGE * timeout lets us CWARN for visibility of sluggish LNDs */ - lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(LONG_UNLINK), - cfs_time_seconds(1), NULL, NULL); - rc = l_wait_event(*wq, !ptlrpc_client_bulk_active(req), &lwi); - if (rc == 0) { + int cnt = 0; + while (cnt < LONG_UNLINK && + (rc = wait_event_idle_timeout(*wq, + !ptlrpc_client_bulk_active(req), + HZ)) == 0) + cnt += 1; + if (rc > 0) { ptlrpc_rqphase_move(req, req->rq_next_phase); return 1; } - LASSERT(rc == -ETIMEDOUT); DEBUG_REQ(D_WARNING, req, "Unexpectedly long timeout: desc %p", desc); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c index a64e125df95f..f73463ac401f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c @@ -260,17 +260,16 @@ lustre_get_emerg_rs(struct ptlrpc_service_part *svcpt) /* See if we have anything in a pool, and wait if nothing */ while (list_empty(&svcpt->scp_rep_idle)) { - struct l_wait_info lwi; int rc; spin_unlock(&svcpt->scp_rep_lock); /* If we cannot get anything for some long time, we better * bail out instead of waiting infinitely */ - lwi = LWI_TIMEOUT(cfs_time_seconds(10), NULL, NULL); - rc = l_wait_event(svcpt->scp_rep_waitq, - !list_empty(&svcpt->scp_rep_idle), &lwi); - if (rc != 0) + rc = wait_event_idle_timeout(svcpt->scp_rep_waitq, + !list_empty(&svcpt->scp_rep_idle), + 10 * HZ); + if (rc == 0) goto out; spin_lock(&svcpt->scp_rep_lock); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index fe6b47bfe8be..0775b7a048bb 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -141,7 +141,7 @@ static long pinger_check_timeout(unsigned long time) } mutex_unlock(&pinger_mutex); - return cfs_time_sub(cfs_time_add(time, cfs_time_seconds(timeout)), + return cfs_time_sub(cfs_time_add(time, timeout * HZ), cfs_time_current()); } @@ -217,37 +217,29 @@ static void ptlrpc_pinger_process_import(struct obd_import *imp, } } -static int ptlrpc_pinger_main(void *arg) -{ - struct ptlrpc_thread *thread = arg; - - /* Record that the thread is running */ - thread_set_flags(thread, SVC_RUNNING); - wake_up(&thread->t_ctl_waitq); +static struct workqueue_struct *pinger_wq; +static void ptlrpc_pinger_main(struct work_struct *ws); +static DECLARE_DELAYED_WORK(ping_work, ptlrpc_pinger_main); - /* And now, loop forever, pinging as needed. */ - while (1) { - unsigned long this_ping = cfs_time_current(); - struct l_wait_info lwi; - long time_to_next_wake; - struct timeout_item *item; - struct list_head *iter; +static void ptlrpc_pinger_main(struct work_struct *ws) +{ + unsigned long this_ping = cfs_time_current(); + long time_to_next_wake; + struct timeout_item *item; + struct obd_import *imp; + do { mutex_lock(&pinger_mutex); list_for_each_entry(item, &timeout_list, ti_chain) { item->ti_cb(item, item->ti_cb_data); } - list_for_each(iter, &pinger_imports) { - struct obd_import *imp = - list_entry(iter, struct obd_import, - imp_pinger_chain); - + list_for_each_entry(imp, &pinger_imports, imp_pinger_chain) { ptlrpc_pinger_process_import(imp, this_ping); /* obd_timeout might have changed */ if (imp->imp_pingable && imp->imp_next_ping && cfs_time_after(imp->imp_next_ping, cfs_time_add(this_ping, - cfs_time_seconds(PING_INTERVAL)))) + PING_INTERVAL * HZ))) ptlrpc_update_next_ping(imp, 0); } mutex_unlock(&pinger_mutex); @@ -264,55 +256,25 @@ static int ptlrpc_pinger_main(void *arg) CDEBUG(D_INFO, "next wakeup in " CFS_DURATION_T " (%ld)\n", time_to_next_wake, cfs_time_add(this_ping, - cfs_time_seconds(PING_INTERVAL))); - if (time_to_next_wake > 0) { - lwi = LWI_TIMEOUT(max_t(long, time_to_next_wake, - cfs_time_seconds(1)), - NULL, NULL); - l_wait_event(thread->t_ctl_waitq, - thread_is_stopping(thread) || - thread_is_event(thread), - &lwi); - if (thread_test_and_clear_flags(thread, SVC_STOPPING)) - break; - /* woken after adding import to reset timer */ - thread_test_and_clear_flags(thread, SVC_EVENT); - } - } - - thread_set_flags(thread, SVC_STOPPED); - wake_up(&thread->t_ctl_waitq); + PING_INTERVAL * HZ)); + } while (time_to_next_wake <= 0); - CDEBUG(D_NET, "pinger thread exiting, process %d\n", current_pid()); - return 0; + queue_delayed_work(pinger_wq, &ping_work, + round_jiffies_up_relative(time_to_next_wake)); } -static struct ptlrpc_thread pinger_thread; - int ptlrpc_start_pinger(void) { - struct l_wait_info lwi = { 0 }; - struct task_struct *task; - int rc; - - if (!thread_is_init(&pinger_thread) && - !thread_is_stopped(&pinger_thread)) + if (pinger_wq) return -EALREADY; - init_waitqueue_head(&pinger_thread.t_ctl_waitq); - - strcpy(pinger_thread.t_name, "ll_ping"); - - task = kthread_run(ptlrpc_pinger_main, &pinger_thread, - pinger_thread.t_name); - if (IS_ERR(task)) { - rc = PTR_ERR(task); - CERROR("cannot start pinger thread: rc = %d\n", rc); - return rc; + pinger_wq = alloc_workqueue("ptlrpc_pinger", WQ_MEM_RECLAIM, 1); + if (!pinger_wq) { + CERROR("cannot start pinger workqueue\n"); + return -ENOMEM; } - l_wait_event(pinger_thread.t_ctl_waitq, - thread_is_running(&pinger_thread), &lwi); + queue_delayed_work(pinger_wq, &ping_work, 0); return 0; } @@ -320,19 +282,15 @@ static int ptlrpc_pinger_remove_timeouts(void); int ptlrpc_stop_pinger(void) { - struct l_wait_info lwi = { 0 }; int rc = 0; - if (thread_is_init(&pinger_thread) || - thread_is_stopped(&pinger_thread)) + if (!pinger_wq) return -EALREADY; ptlrpc_pinger_remove_timeouts(); - thread_set_flags(&pinger_thread, SVC_STOPPING); - wake_up(&pinger_thread.t_ctl_waitq); - - l_wait_event(pinger_thread.t_ctl_waitq, - thread_is_stopped(&pinger_thread), &lwi); + cancel_delayed_work_sync(&ping_work); + destroy_workqueue(pinger_wq); + pinger_wq = NULL; return rc; } @@ -515,6 +473,5 @@ static int ptlrpc_pinger_remove_timeouts(void) void ptlrpc_pinger_wake_up(void) { - thread_add_flags(&pinger_thread, SVC_EVENT); - wake_up(&pinger_thread.t_ctl_waitq); + mod_delayed_work(pinger_wq, &ping_work, 0); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h index f9decbd1459d..b7a8d7537a66 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_internal.h @@ -68,7 +68,7 @@ void ptlrpc_request_cache_free(struct ptlrpc_request *req); void ptlrpc_init_xid(void); void ptlrpc_set_add_new_req(struct ptlrpcd_ctl *pc, struct ptlrpc_request *req); -int ptlrpc_expired_set(void *data); +void ptlrpc_expired_set(struct ptlrpc_request_set *set); int ptlrpc_set_next_timeout(struct ptlrpc_request_set *set); void ptlrpc_resend_req(struct ptlrpc_request *request); void ptlrpc_set_bulk_mbits(struct ptlrpc_request *req); diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c index 131fc6d9646e..38923418669f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c @@ -45,6 +45,42 @@ extern spinlock_t ptlrpc_last_xid_lock; extern spinlock_t ptlrpc_rs_debug_lock; #endif +DEFINE_MUTEX(ptlrpc_startup); +static int ptlrpc_active = 0; + +int ptlrpc_inc_ref(void) +{ + int rc = 0; + + mutex_lock(&ptlrpc_startup); + if (ptlrpc_active++ == 0) { + ptlrpc_put_connection_superhack = ptlrpc_connection_put; + + rc = ptlrpc_init_portals(); + if (!rc) { + rc= ptlrpc_start_pinger(); + if (rc) + ptlrpc_exit_portals(); + } + if (rc) + ptlrpc_active--; + } + mutex_unlock(&ptlrpc_startup); + return rc; +} +EXPORT_SYMBOL(ptlrpc_inc_ref); + +void ptlrpc_dec_ref(void) +{ + mutex_lock(&ptlrpc_startup); + if (--ptlrpc_active == 0) { + ptlrpc_stop_pinger(); + ptlrpc_exit_portals(); + } + mutex_unlock(&ptlrpc_startup); +} +EXPORT_SYMBOL(ptlrpc_dec_ref); + static int __init ptlrpc_init(void) { int rc, cleanup_phase = 0; @@ -71,24 +107,12 @@ static int __init ptlrpc_init(void) if (rc) goto cleanup; - cleanup_phase = 2; - rc = ptlrpc_init_portals(); - if (rc) - goto cleanup; - cleanup_phase = 3; rc = ptlrpc_connection_init(); if (rc) goto cleanup; - cleanup_phase = 4; - ptlrpc_put_connection_superhack = ptlrpc_connection_put; - - rc = ptlrpc_start_pinger(); - if (rc) - goto cleanup; - cleanup_phase = 5; rc = ldlm_init(); if (rc) @@ -122,15 +146,9 @@ cleanup: ldlm_exit(); /* Fall through */ case 5: - ptlrpc_stop_pinger(); - /* Fall through */ - case 4: ptlrpc_connection_fini(); /* Fall through */ case 3: - ptlrpc_exit_portals(); - /* Fall through */ - case 2: ptlrpc_request_cache_fini(); /* Fall through */ case 1: @@ -150,8 +168,6 @@ static void __exit ptlrpc_exit(void) ptlrpc_nrs_fini(); sptlrpc_fini(); ldlm_exit(); - ptlrpc_stop_pinger(); - ptlrpc_exit_portals(); ptlrpc_request_cache_fini(); ptlrpc_hr_fini(); ptlrpc_connection_fini(); diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c index 8b865294d933..c0fa13942bd8 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c @@ -197,17 +197,14 @@ ptlrpcd_select_pc(struct ptlrpc_request *req) static int ptlrpcd_steal_rqset(struct ptlrpc_request_set *des, struct ptlrpc_request_set *src) { - struct list_head *tmp, *pos; - struct ptlrpc_request *req; + struct ptlrpc_request *req, *tmp; int rc = 0; spin_lock(&src->set_new_req_lock); if (likely(!list_empty(&src->set_new_requests))) { - list_for_each_safe(pos, tmp, &src->set_new_requests) { - req = list_entry(pos, struct ptlrpc_request, - rq_set_chain); + list_for_each_entry_safe(req, tmp, &src->set_new_requests, rq_set_chain) req->rq_set = des; - } + list_splice_init(&src->set_new_requests, &des->set_requests); rc = atomic_read(&src->set_new_count); atomic_add(rc, &des->set_remaining); @@ -230,12 +227,13 @@ void ptlrpcd_add_req(struct ptlrpc_request *req) spin_lock(&req->rq_lock); if (req->rq_invalid_rqset) { - struct l_wait_info lwi = LWI_TIMEOUT(cfs_time_seconds(5), - back_to_sleep, NULL); - req->rq_invalid_rqset = 0; spin_unlock(&req->rq_lock); - l_wait_event(req->rq_set_waitq, !req->rq_set, &lwi); + if (wait_event_idle_timeout(req->rq_set_waitq, + !req->rq_set, + 5 * HZ) == 0) + wait_event_idle(req->rq_set_waitq, + !req->rq_set); } else if (req->rq_set) { /* If we have a valid "rq_set", just reuse it to avoid double * linked. @@ -272,8 +270,7 @@ static inline void ptlrpc_reqset_get(struct ptlrpc_request_set *set) */ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) { - struct list_head *tmp, *pos; - struct ptlrpc_request *req; + struct ptlrpc_request *req, *tmp; struct ptlrpc_request_set *set = pc->pc_set; int rc = 0; int rc2; @@ -319,8 +316,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) /* NB: ptlrpc_check_set has already moved completed request at the * head of seq::set_requests */ - list_for_each_safe(pos, tmp, &set->set_requests) { - req = list_entry(pos, struct ptlrpc_request, rq_set_chain); + list_for_each_entry_safe(req, tmp, &set->set_requests, rq_set_chain) { if (req->rq_phase != RQ_PHASE_COMPLETE) break; @@ -434,16 +430,17 @@ static int ptlrpcd(void *arg) * new_req_list and ptlrpcd_check() moves them into the set. */ do { - struct l_wait_info lwi; int timeout; timeout = ptlrpc_set_next_timeout(set); - lwi = LWI_TIMEOUT(cfs_time_seconds(timeout ? timeout : 1), - ptlrpc_expired_set, set); lu_context_enter(&env.le_ctx); lu_context_enter(env.le_ses); - l_wait_event(set->set_waitq, ptlrpcd_check(&env, pc), &lwi); + if (wait_event_idle_timeout(set->set_waitq, + ptlrpcd_check(&env, pc), + (timeout ? timeout : 1) * HZ) == 0) + ptlrpc_expired_set(set); + lu_context_exit(&env.le_ctx); lu_context_exit(env.le_ses); diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c index e4d3f23e9f3a..2ea0a7ff87dd 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/recover.c +++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c @@ -66,8 +66,7 @@ void ptlrpc_initiate_recovery(struct obd_import *imp) int ptlrpc_replay_next(struct obd_import *imp, int *inflight) { int rc = 0; - struct list_head *tmp, *pos; - struct ptlrpc_request *req = NULL; + struct ptlrpc_request *req = NULL, *pos; __u64 last_transno; *inflight = 0; @@ -86,8 +85,8 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight) /* Replay all the committed open requests on committed_list first */ if (!list_empty(&imp->imp_committed_list)) { - tmp = imp->imp_committed_list.prev; - req = list_entry(tmp, struct ptlrpc_request, rq_replay_list); + req = list_last_entry(&imp->imp_committed_list, + struct ptlrpc_request, rq_replay_list); /* The last request on committed_list hasn't been replayed */ if (req->rq_transno > last_transno) { @@ -119,13 +118,13 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight) * the imp_replay_list */ if (!req) { - list_for_each_safe(tmp, pos, &imp->imp_replay_list) { - req = list_entry(tmp, struct ptlrpc_request, - rq_replay_list); - - if (req->rq_transno > last_transno) + struct ptlrpc_request *tmp; + list_for_each_entry_safe(tmp, pos, &imp->imp_replay_list, + rq_replay_list) { + if (tmp->rq_transno > last_transno) { + req = tmp; break; - req = NULL; + } } } @@ -211,13 +210,10 @@ int ptlrpc_resend(struct obd_import *imp) */ void ptlrpc_wake_delayed(struct obd_import *imp) { - struct list_head *tmp, *pos; - struct ptlrpc_request *req; + struct ptlrpc_request *req, *pos; spin_lock(&imp->imp_lock); - list_for_each_safe(tmp, pos, &imp->imp_delayed_list) { - req = list_entry(tmp, struct ptlrpc_request, rq_list); - + list_for_each_entry_safe(req, pos, &imp->imp_delayed_list, rq_list) { DEBUG_REQ(D_HA, req, "waking (set %p):", req->rq_set); ptlrpc_client_wake_req(req); } @@ -346,17 +342,15 @@ int ptlrpc_recover_import(struct obd_import *imp, char *new_uuid, int async) goto out; if (!async) { - struct l_wait_info lwi; - int secs = cfs_time_seconds(obd_timeout); - CDEBUG(D_HA, "%s: recovery started, waiting %u seconds\n", - obd2cli_tgt(imp->imp_obd), secs); + obd2cli_tgt(imp->imp_obd), obd_timeout); - lwi = LWI_TIMEOUT(secs, NULL, NULL); - rc = l_wait_event(imp->imp_recovery_waitq, - !ptlrpc_import_in_recovery(imp), &lwi); + rc = wait_event_idle_timeout(imp->imp_recovery_waitq, + !ptlrpc_import_in_recovery(imp), + obd_timeout * HZ); CDEBUG(D_HA, "%s: recovery finished\n", obd2cli_tgt(imp->imp_obd)); + rc = rc ? 0 : -ETIMEDOUT; } out: diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index 617e004d00f8..3cb1e075f077 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -339,11 +339,9 @@ static int import_sec_validate_get(struct obd_import *imp, } *sec = sptlrpc_import_sec_ref(imp); - /* Only output an error when the import is still active */ if (!*sec) { - if (list_empty(&imp->imp_zombie_chain)) - CERROR("import %p (%s) with no sec\n", - imp, ptlrpc_import_state_name(imp->imp_state)); + CERROR("import %p (%s) with no sec\n", + imp, ptlrpc_import_state_name(imp->imp_state)); return -EACCES; } @@ -442,7 +440,7 @@ int sptlrpc_req_ctx_switch(struct ptlrpc_request *req, /* save request message */ reqmsg_size = req->rq_reqlen; if (reqmsg_size != 0) { - reqmsg = libcfs_kvzalloc(reqmsg_size, GFP_NOFS); + reqmsg = kvzalloc(reqmsg_size, GFP_NOFS); if (!reqmsg) return -ENOMEM; memcpy(reqmsg, req->rq_reqmsg, reqmsg_size); @@ -554,9 +552,8 @@ int ctx_check_refresh(struct ptlrpc_cli_ctx *ctx) } static -int ctx_refresh_timeout(void *data) +int ctx_refresh_timeout(struct ptlrpc_request *req) { - struct ptlrpc_request *req = data; int rc; /* conn_cnt is needed in expire_one_request */ @@ -575,10 +572,8 @@ int ctx_refresh_timeout(void *data) } static -void ctx_refresh_interrupt(void *data) +void ctx_refresh_interrupt(struct ptlrpc_request *req) { - struct ptlrpc_request *req = data; - spin_lock(&req->rq_lock); req->rq_intr = 1; spin_unlock(&req->rq_lock); @@ -611,7 +606,6 @@ int sptlrpc_req_refresh_ctx(struct ptlrpc_request *req, long timeout) { struct ptlrpc_cli_ctx *ctx = req->rq_cli_ctx; struct ptlrpc_sec *sec; - struct l_wait_info lwi; int rc; LASSERT(ctx); @@ -743,10 +737,28 @@ again: req->rq_restart = 0; spin_unlock(&req->rq_lock); - lwi = LWI_TIMEOUT_INTR(msecs_to_jiffies(timeout * MSEC_PER_SEC), - ctx_refresh_timeout, ctx_refresh_interrupt, - req); - rc = l_wait_event(req->rq_reply_waitq, ctx_check_refresh(ctx), &lwi); + rc = wait_event_idle_timeout(req->rq_reply_waitq, + ctx_check_refresh(ctx), + timeout * HZ); + if (rc == 0 && ctx_refresh_timeout(req) == 0) { + /* Keep waiting, but enable some signals */ + rc = l_wait_event_abortable(req->rq_reply_waitq, + ctx_check_refresh(ctx)); + if (rc == 0) + rc = 1; + } + + if (rc > 0) + /* condition is true */ + rc = 0; + else if (rc == 0) + /* Timed out */ + rc = -ETIMEDOUT; + else { + /* Aborted by signal */ + rc = -EINTR; + ctx_refresh_interrupt(req); + } /* * following cases could lead us here: @@ -1075,7 +1087,7 @@ int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req, early_size = req->rq_nob_received; early_bufsz = size_roundup_power2(early_size); - early_buf = libcfs_kvzalloc(early_bufsz, GFP_NOFS); + early_buf = kvzalloc(early_bufsz, GFP_NOFS); if (!early_buf) { rc = -ENOMEM; goto err_req; diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 134ee727e8b7..625b9520d78f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -375,9 +375,9 @@ static inline void enc_pools_alloc(void) { LASSERT(page_pools.epp_max_pools); page_pools.epp_pools = - libcfs_kvzalloc(page_pools.epp_max_pools * + kvzalloc(page_pools.epp_max_pools * sizeof(*page_pools.epp_pools), - GFP_NOFS); + GFP_KERNEL); } static inline void enc_pools_free(void) @@ -530,7 +530,7 @@ EXPORT_SYMBOL(bulk_sec_desc_unpack); int sptlrpc_get_bulk_checksum(struct ptlrpc_bulk_desc *desc, __u8 alg, void *buf, int buflen) { - struct cfs_crypto_hash_desc *hdesc; + struct ahash_request *hdesc; int hashsize; unsigned int bufsize; int i, err; diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c index 8d1e0edfcede..2c8bad7b7877 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c @@ -55,7 +55,6 @@ static spinlock_t sec_gc_list_lock; static LIST_HEAD(sec_gc_ctx_list); static spinlock_t sec_gc_ctx_list_lock; -static struct ptlrpc_thread sec_gc_thread; static atomic_t sec_gc_wait_del = ATOMIC_INIT(0); void sptlrpc_gc_add_sec(struct ptlrpc_sec *sec) @@ -139,95 +138,53 @@ static void sec_do_gc(struct ptlrpc_sec *sec) sec->ps_gc_next = ktime_get_real_seconds() + sec->ps_gc_interval; } -static int sec_gc_main(void *arg) -{ - struct ptlrpc_thread *thread = arg; - struct l_wait_info lwi; - - unshare_fs_struct(); +static void sec_gc_main(struct work_struct *ws); +static DECLARE_DELAYED_WORK(sec_gc_work, sec_gc_main); - /* Record that the thread is running */ - thread_set_flags(thread, SVC_RUNNING); - wake_up(&thread->t_ctl_waitq); - - while (1) { - struct ptlrpc_sec *sec; +static void sec_gc_main(struct work_struct *ws) +{ + struct ptlrpc_sec *sec; - thread_clear_flags(thread, SVC_SIGNAL); - sec_process_ctx_list(); + sec_process_ctx_list(); again: - /* go through sec list do gc. - * FIXME here we iterate through the whole list each time which - * is not optimal. we perhaps want to use balanced binary tree - * to trace each sec as order of expiry time. - * another issue here is we wakeup as fixed interval instead of - * according to each sec's expiry time + /* go through sec list do gc. + * FIXME here we iterate through the whole list each time which + * is not optimal. we perhaps want to use balanced binary tree + * to trace each sec as order of expiry time. + * another issue here is we wakeup as fixed interval instead of + * according to each sec's expiry time + */ + mutex_lock(&sec_gc_mutex); + list_for_each_entry(sec, &sec_gc_list, ps_gc_list) { + /* if someone is waiting to be deleted, let it + * proceed as soon as possible. */ - mutex_lock(&sec_gc_mutex); - list_for_each_entry(sec, &sec_gc_list, ps_gc_list) { - /* if someone is waiting to be deleted, let it - * proceed as soon as possible. - */ - if (atomic_read(&sec_gc_wait_del)) { - CDEBUG(D_SEC, "deletion pending, start over\n"); - mutex_unlock(&sec_gc_mutex); - goto again; - } - - sec_do_gc(sec); + if (atomic_read(&sec_gc_wait_del)) { + CDEBUG(D_SEC, "deletion pending, start over\n"); + mutex_unlock(&sec_gc_mutex); + goto again; } - mutex_unlock(&sec_gc_mutex); - - /* check ctx list again before sleep */ - sec_process_ctx_list(); - lwi = LWI_TIMEOUT(msecs_to_jiffies(SEC_GC_INTERVAL * MSEC_PER_SEC), - NULL, NULL); - l_wait_event(thread->t_ctl_waitq, - thread_is_stopping(thread) || - thread_is_signal(thread), - &lwi); - - if (thread_test_and_clear_flags(thread, SVC_STOPPING)) - break; + sec_do_gc(sec); } + mutex_unlock(&sec_gc_mutex); - thread_set_flags(thread, SVC_STOPPED); - wake_up(&thread->t_ctl_waitq); - return 0; + /* check ctx list again before sleep */ + sec_process_ctx_list(); + schedule_delayed_work(&sec_gc_work, SEC_GC_INTERVAL * HZ); } int sptlrpc_gc_init(void) { - struct l_wait_info lwi = { 0 }; - struct task_struct *task; - mutex_init(&sec_gc_mutex); spin_lock_init(&sec_gc_list_lock); spin_lock_init(&sec_gc_ctx_list_lock); - /* initialize thread control */ - memset(&sec_gc_thread, 0, sizeof(sec_gc_thread)); - init_waitqueue_head(&sec_gc_thread.t_ctl_waitq); - - task = kthread_run(sec_gc_main, &sec_gc_thread, "sptlrpc_gc"); - if (IS_ERR(task)) { - CERROR("can't start gc thread: %ld\n", PTR_ERR(task)); - return PTR_ERR(task); - } - - l_wait_event(sec_gc_thread.t_ctl_waitq, - thread_is_running(&sec_gc_thread), &lwi); + schedule_delayed_work(&sec_gc_work, 0); return 0; } void sptlrpc_gc_fini(void) { - struct l_wait_info lwi = { 0 }; - - thread_set_flags(&sec_gc_thread, SVC_STOPPING); - wake_up(&sec_gc_thread.t_ctl_waitq); - - l_wait_event(sec_gc_thread.t_ctl_waitq, - thread_is_stopped(&sec_gc_thread), &lwi); + cancel_delayed_work_sync(&sec_gc_work); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c index 80cea0b24693..ecc387d1b9b4 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_null.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_null.c @@ -158,7 +158,7 @@ int null_alloc_reqbuf(struct ptlrpc_sec *sec, int alloc_size = size_roundup_power2(msgsize); LASSERT(!req->rq_pool); - req->rq_reqbuf = libcfs_kvzalloc(alloc_size, GFP_NOFS); + req->rq_reqbuf = kvzalloc(alloc_size, GFP_NOFS); if (!req->rq_reqbuf) return -ENOMEM; @@ -201,7 +201,7 @@ int null_alloc_repbuf(struct ptlrpc_sec *sec, msgsize = size_roundup_power2(msgsize); - req->rq_repbuf = libcfs_kvzalloc(msgsize, GFP_NOFS); + req->rq_repbuf = kvzalloc(msgsize, GFP_NOFS); if (!req->rq_repbuf) return -ENOMEM; @@ -246,7 +246,7 @@ int null_enlarge_reqbuf(struct ptlrpc_sec *sec, if (req->rq_reqbuf_len < newmsg_size) { alloc_size = size_roundup_power2(newmsg_size); - newbuf = libcfs_kvzalloc(alloc_size, GFP_NOFS); + newbuf = kvzalloc(alloc_size, GFP_NOFS); if (!newbuf) return -ENOMEM; @@ -317,7 +317,7 @@ int null_alloc_rs(struct ptlrpc_request *req, int msgsize) /* pre-allocated */ LASSERT(rs->rs_size >= rs_size); } else { - rs = libcfs_kvzalloc(rs_size, GFP_NOFS); + rs = kvzalloc(rs_size, GFP_NOFS); if (!rs) return -ENOMEM; diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c index 44e34056515b..ec3d9af76b17 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c @@ -562,7 +562,7 @@ int plain_alloc_reqbuf(struct ptlrpc_sec *sec, LASSERT(!req->rq_pool); alloc_len = size_roundup_power2(alloc_len); - req->rq_reqbuf = libcfs_kvzalloc(alloc_len, GFP_NOFS); + req->rq_reqbuf = kvzalloc(alloc_len, GFP_NOFS); if (!req->rq_reqbuf) return -ENOMEM; @@ -620,7 +620,7 @@ int plain_alloc_repbuf(struct ptlrpc_sec *sec, alloc_len = size_roundup_power2(alloc_len); - req->rq_repbuf = libcfs_kvzalloc(alloc_len, GFP_NOFS); + req->rq_repbuf = kvzalloc(alloc_len, GFP_NOFS); if (!req->rq_repbuf) return -ENOMEM; @@ -671,7 +671,7 @@ int plain_enlarge_reqbuf(struct ptlrpc_sec *sec, if (req->rq_reqbuf_len < newbuf_size) { newbuf_size = size_roundup_power2(newbuf_size); - newbuf = libcfs_kvzalloc(newbuf_size, GFP_NOFS); + newbuf = kvzalloc(newbuf_size, GFP_NOFS); if (!newbuf) return -ENOMEM; @@ -808,7 +808,7 @@ int plain_alloc_rs(struct ptlrpc_request *req, int msgsize) /* pre-allocated */ LASSERT(rs->rs_size >= rs_size); } else { - rs = libcfs_kvzalloc(rs_size, GFP_NOFS); + rs = kvzalloc(rs_size, GFP_NOFS); if (!rs) return -ENOMEM; diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index 63be6e7273f3..f37364e00dfe 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -83,10 +83,10 @@ ptlrpc_alloc_rqbd(struct ptlrpc_service_part *svcpt) rqbd->rqbd_cbid.cbid_fn = request_in_callback; rqbd->rqbd_cbid.cbid_arg = rqbd; INIT_LIST_HEAD(&rqbd->rqbd_reqs); - rqbd->rqbd_buffer = libcfs_kvzalloc_cpt(svc->srv_cptable, - svcpt->scp_cpt, - svc->srv_buf_size, - GFP_KERNEL); + rqbd->rqbd_buffer = kvzalloc_node(svc->srv_buf_size, GFP_KERNEL, + cfs_cpt_spread_node(svc->srv_cptable, + svcpt->scp_cpt)); + if (!rqbd->rqbd_buffer) { kfree(rqbd); return NULL; @@ -726,8 +726,6 @@ static void ptlrpc_server_drop_request(struct ptlrpc_request *req) struct ptlrpc_service_part *svcpt = rqbd->rqbd_svcpt; struct ptlrpc_service *svc = svcpt->scp_service; int refcount; - struct list_head *tmp; - struct list_head *nxt; if (!atomic_dec_and_test(&req->rq_refcount)) return; @@ -776,9 +774,7 @@ static void ptlrpc_server_drop_request(struct ptlrpc_request *req) /* remove rqbd's reqs from svc's req history while * I've got the service lock */ - list_for_each(tmp, &rqbd->rqbd_reqs) { - req = list_entry(tmp, struct ptlrpc_request, - rq_list); + list_for_each_entry(req, &rqbd->rqbd_reqs, rq_list) { /* Track the highest culled req seq */ if (req->rq_history_seq > svcpt->scp_hist_seq_culled) { @@ -790,10 +786,9 @@ static void ptlrpc_server_drop_request(struct ptlrpc_request *req) spin_unlock(&svcpt->scp_lock); - list_for_each_safe(tmp, nxt, &rqbd->rqbd_reqs) { - req = list_entry(rqbd->rqbd_reqs.next, - struct ptlrpc_request, - rq_list); + while ((req = list_first_entry_or_null( + &rqbd->rqbd_reqs, + struct ptlrpc_request, rq_list))) { list_del(&req->rq_list); ptlrpc_server_free_request(req); } @@ -1068,7 +1063,7 @@ static int ptlrpc_at_send_early_reply(struct ptlrpc_request *req) reqcopy = ptlrpc_request_cache_alloc(GFP_NOFS); if (!reqcopy) return -ENOMEM; - reqmsg = libcfs_kvzalloc(req->rq_reqlen, GFP_NOFS); + reqmsg = kvzalloc(req->rq_reqlen, GFP_NOFS); if (!reqmsg) { rc = -ENOMEM; goto out_free; @@ -1897,15 +1892,6 @@ ptlrpc_check_rqbd_pool(struct ptlrpc_service_part *svcpt) } } -static int -ptlrpc_retry_rqbds(void *arg) -{ - struct ptlrpc_service_part *svcpt = arg; - - svcpt->scp_rqbd_timeout = 0; - return -ETIMEDOUT; -} - static inline int ptlrpc_threads_enough(struct ptlrpc_service_part *svcpt) { @@ -1968,13 +1954,17 @@ ptlrpc_server_request_incoming(struct ptlrpc_service_part *svcpt) return !list_empty(&svcpt->scp_req_incoming); } +/* We perfer lifo queuing, but kernel doesn't provide that yet. */ +#ifndef wait_event_idle_exclusive_lifo +#define wait_event_idle_exclusive_lifo wait_event_idle_exclusive +#define wait_event_idle_exclusive_lifo_timeout wait_event_idle_exclusive_timeout +#endif + static __attribute__((__noinline__)) int ptlrpc_wait_event(struct ptlrpc_service_part *svcpt, struct ptlrpc_thread *thread) { /* Don't exit while there are replies to be handled */ - struct l_wait_info lwi = LWI_TIMEOUT(svcpt->scp_rqbd_timeout, - ptlrpc_retry_rqbds, svcpt); /* XXX: Add this back when libcfs watchdog is merged upstream lc_watchdog_disable(thread->t_watchdog); @@ -1982,13 +1972,25 @@ ptlrpc_wait_event(struct ptlrpc_service_part *svcpt, cond_resched(); - l_wait_event_exclusive_head(svcpt->scp_waitq, - ptlrpc_thread_stopping(thread) || - ptlrpc_server_request_incoming(svcpt) || - ptlrpc_server_request_pending(svcpt, - false) || - ptlrpc_rqbd_pending(svcpt) || - ptlrpc_at_check(svcpt), &lwi); + if (svcpt->scp_rqbd_timeout == 0) + wait_event_idle_exclusive_lifo( + svcpt->scp_waitq, + ptlrpc_thread_stopping(thread) || + ptlrpc_server_request_incoming(svcpt) || + ptlrpc_server_request_pending(svcpt, + false) || + ptlrpc_rqbd_pending(svcpt) || + ptlrpc_at_check(svcpt)); + else if (0 == wait_event_idle_exclusive_lifo_timeout( + svcpt->scp_waitq, + ptlrpc_thread_stopping(thread) || + ptlrpc_server_request_incoming(svcpt) || + ptlrpc_server_request_pending(svcpt, + false) || + ptlrpc_rqbd_pending(svcpt) || + ptlrpc_at_check(svcpt), + svcpt->scp_rqbd_timeout)) + svcpt->scp_rqbd_timeout = 0; if (ptlrpc_thread_stopping(thread)) return -EINTR; @@ -2044,7 +2046,7 @@ static int ptlrpc_main(void *arg) goto out; } - env = kzalloc(sizeof(*env), GFP_NOFS); + env = kzalloc(sizeof(*env), GFP_KERNEL); if (!env) { rc = -ENOMEM; goto out_srv_fini; @@ -2070,7 +2072,7 @@ static int ptlrpc_main(void *arg) } /* Alloc reply state structure for this one */ - rs = libcfs_kvzalloc(svc->srv_max_reply_size, GFP_NOFS); + rs = kvzalloc(svc->srv_max_reply_size, GFP_KERNEL); if (!rs) { rc = -ENOMEM; goto out_srv_fini; @@ -2149,7 +2151,7 @@ static int ptlrpc_main(void *arg) * Wait for a timeout (unless something else * happens) before I try again */ - svcpt->scp_rqbd_timeout = cfs_time_seconds(1) / 10; + svcpt->scp_rqbd_timeout = HZ / 10; CDEBUG(D_RPCTRACE, "Posted buffers: %d\n", svcpt->scp_nrqbds_posted); } @@ -2233,7 +2235,7 @@ static int ptlrpc_hr_main(void *arg) wake_up(&ptlrpc_hr.hr_waitq); while (!ptlrpc_hr.hr_stopping) { - l_wait_condition(hrt->hrt_waitq, hrt_dont_sleep(hrt, &replies)); + wait_event_idle(hrt->hrt_waitq, hrt_dont_sleep(hrt, &replies)); while (!list_empty(&replies)) { struct ptlrpc_reply_state *rs; @@ -2312,7 +2314,6 @@ static int ptlrpc_start_hr_threads(void) static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt) { - struct l_wait_info lwi = { 0 }; struct ptlrpc_thread *thread; LIST_HEAD(zombie); @@ -2341,8 +2342,8 @@ static void ptlrpc_svcpt_stop_threads(struct ptlrpc_service_part *svcpt) CDEBUG(D_INFO, "waiting for stopping-thread %s #%u\n", svcpt->scp_service->srv_thread_name, thread->t_id); - l_wait_event(thread->t_ctl_waitq, - thread_is_stopped(thread), &lwi); + wait_event_idle(thread->t_ctl_waitq, + thread_is_stopped(thread)); spin_lock(&svcpt->scp_lock); } @@ -2403,7 +2404,6 @@ int ptlrpc_start_threads(struct ptlrpc_service *svc) int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait) { - struct l_wait_info lwi = { 0 }; struct ptlrpc_thread *thread; struct ptlrpc_service *svc; struct task_struct *task; @@ -2499,9 +2499,8 @@ int ptlrpc_start_thread(struct ptlrpc_service_part *svcpt, int wait) if (!wait) return 0; - l_wait_event(thread->t_ctl_waitq, - thread_is_running(thread) || thread_is_stopped(thread), - &lwi); + wait_event_idle(thread->t_ctl_waitq, + thread_is_running(thread) || thread_is_stopped(thread)); rc = thread_is_stopped(thread) ? thread->t_id : 0; return rc; @@ -2591,13 +2590,12 @@ static void ptlrpc_wait_replies(struct ptlrpc_service_part *svcpt) { while (1) { int rc; - struct l_wait_info lwi = LWI_TIMEOUT(cfs_time_seconds(10), - NULL, NULL); - rc = l_wait_event(svcpt->scp_waitq, - atomic_read(&svcpt->scp_nreps_difficult) == 0, - &lwi); - if (rc == 0) + rc = wait_event_idle_timeout( + svcpt->scp_waitq, + atomic_read(&svcpt->scp_nreps_difficult) == 0, + 10 * HZ); + if (rc > 0) break; CWARN("Unexpectedly long timeout %s %p\n", svcpt->scp_service->srv_name, svcpt->scp_service); @@ -2622,7 +2620,7 @@ ptlrpc_service_unlink_rqbd(struct ptlrpc_service *svc) { struct ptlrpc_service_part *svcpt; struct ptlrpc_request_buffer_desc *rqbd; - struct l_wait_info lwi; + int cnt; int rc; int i; @@ -2662,12 +2660,13 @@ ptlrpc_service_unlink_rqbd(struct ptlrpc_service *svc) * the HUGE timeout lets us CWARN for visibility * of sluggish LNDs */ - lwi = LWI_TIMEOUT_INTERVAL( - cfs_time_seconds(LONG_UNLINK), - cfs_time_seconds(1), NULL, NULL); - rc = l_wait_event(svcpt->scp_waitq, - svcpt->scp_nrqbds_posted == 0, &lwi); - if (rc == -ETIMEDOUT) { + cnt = 0; + while (cnt < LONG_UNLINK && + (rc = wait_event_idle_timeout(svcpt->scp_waitq, + svcpt->scp_nrqbds_posted == 0, + HZ)) == 0) + cnt++; + if (rc == 0) { CWARN("Service %s waiting for request buffers\n", svcpt->scp_service->srv_name); } diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c index 3dda8d81bf0b..8f2833526f7f 100644 --- a/drivers/staging/most/core.c +++ b/drivers/staging/most/core.c @@ -583,6 +583,7 @@ static ssize_t components_show(struct device_driver *drv, char *buf) } return offs; } + /** * split_string - parses buf and extracts ':' separated substrings. * @@ -915,7 +916,6 @@ static void arm_mbo(struct mbo *mbo) unsigned long flags; struct most_channel *c; - BUG_ON((!mbo) || (!mbo->context)); c = mbo->context; if (c->is_poisoned) { @@ -1018,8 +1018,6 @@ static void most_write_completion(struct mbo *mbo) { struct most_channel *c; - BUG_ON((!mbo) || (!mbo->context)); - c = mbo->context; if (mbo->status == MBO_E_INVAL) pr_info("WARN: Tx MBO status: invalid\n"); @@ -1202,7 +1200,6 @@ int most_start_channel(struct most_interface *iface, int id, num_buffer = arm_mbo_chain(c, c->cfg.direction, most_write_completion); if (unlikely(!num_buffer)) { - pr_info("failed to allocate memory\n"); ret = -ENOMEM; goto error; } @@ -1381,7 +1378,6 @@ int most_register_interface(struct most_interface *iface) iface->p = kzalloc(sizeof(*iface->p), GFP_KERNEL); if (!iface->p) { - pr_info("Failed to allocate interface instance\n"); ida_simple_remove(&mdev_id, id); return -ENOMEM; } @@ -1474,7 +1470,8 @@ void most_deregister_interface(struct most_interface *iface) int i; struct most_channel *c; - pr_info("deregistering device %s (%s)\n", dev_name(&iface->dev), iface->description); + pr_info("deregistering device %s (%s)\n", dev_name(&iface->dev), + iface->description); for (i = 0; i < iface->num_channels; i++) { c = iface->p->channel[i]; if (c->pipe0.comp) diff --git a/drivers/staging/most/core.h b/drivers/staging/most/core.h index 74a29163b68a..884bd71fafce 100644 --- a/drivers/staging/most/core.h +++ b/drivers/staging/most/core.h @@ -184,7 +184,7 @@ struct mbo { u16 buffer_length; u16 processed_length; enum mbo_status_flags status; - void (*complete)(struct mbo *); + void (*complete)(struct mbo *mbo); }; /** diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c index 264ad362d858..d20284b49557 100644 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -316,6 +316,7 @@ static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id) row = page_id; cmd.cmd = CMD_READ; cmd.n_addr = 3; + cmd.addr[0] = (u8)((row & 0xff0000) >> 16); cmd.addr[1] = (u8)((row & 0xff00) >> 8); cmd.addr[2] = (u8)(row & 0x00ff); @@ -464,6 +465,7 @@ static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id) row = page_id; cmd.cmd = CMD_PROG_PAGE_EXC; cmd.n_addr = 3; + cmd.addr[0] = (u8)((row & 0xff0000) >> 16); cmd.addr[1] = (u8)((row & 0xff00) >> 8); cmd.addr[2] = (u8)(row & 0x00ff); @@ -579,6 +581,7 @@ static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id) row = block_id; cmd.cmd = CMD_ERASE_BLK; cmd.n_addr = 3; + cmd.addr[0] = (u8)((row & 0xff0000) >> 16); cmd.addr[1] = (u8)((row & 0xff00) >> 8); cmd.addr[2] = (u8)(row & 0x00ff); diff --git a/drivers/staging/mt7621-dma/Kconfig b/drivers/staging/mt7621-dma/Kconfig new file mode 100644 index 000000000000..2423c40099d1 --- /dev/null +++ b/drivers/staging/mt7621-dma/Kconfig @@ -0,0 +1,12 @@ +config DMA_RALINK + tristate "RALINK DMA support" + depends on RALINK && !SOC_RT288X + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + +config MTK_HSDMA + tristate "MTK HSDMA support" + depends on RALINK && SOC_MT7621 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + diff --git a/drivers/staging/mt7621-dma/Makefile b/drivers/staging/mt7621-dma/Makefile new file mode 100644 index 000000000000..d3152d45cf45 --- /dev/null +++ b/drivers/staging/mt7621-dma/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_DMA_RALINK) += ralink-gdma.o +obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o + +ccflags-y += -I$(srctree)/drivers/dma diff --git a/drivers/staging/mt7621-dma/TODO b/drivers/staging/mt7621-dma/TODO new file mode 100644 index 000000000000..fdbc5002c32a --- /dev/null +++ b/drivers/staging/mt7621-dma/TODO @@ -0,0 +1,5 @@ + +- general code review and clean up +- ensure device-tree requirements are documented + +Cc: NeilBrown <neil@brown.name> diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c new file mode 100644 index 000000000000..df6ebf41bdea --- /dev/null +++ b/drivers/staging/mt7621-dma/mtk-hsdma.c @@ -0,0 +1,768 @@ +/* + * Copyright (C) 2015, Michael Lee <igvtee@gmail.com> + * MTK HSDMA support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/irq.h> +#include <linux/of_dma.h> +#include <linux/reset.h> +#include <linux/of_device.h> + +#include "virt-dma.h" + +#define HSDMA_BASE_OFFSET 0x800 + +#define HSDMA_REG_TX_BASE 0x00 +#define HSDMA_REG_TX_CNT 0x04 +#define HSDMA_REG_TX_CTX 0x08 +#define HSDMA_REG_TX_DTX 0x0c +#define HSDMA_REG_RX_BASE 0x100 +#define HSDMA_REG_RX_CNT 0x104 +#define HSDMA_REG_RX_CRX 0x108 +#define HSDMA_REG_RX_DRX 0x10c +#define HSDMA_REG_INFO 0x200 +#define HSDMA_REG_GLO_CFG 0x204 +#define HSDMA_REG_RST_CFG 0x208 +#define HSDMA_REG_DELAY_INT 0x20c +#define HSDMA_REG_FREEQ_THRES 0x210 +#define HSDMA_REG_INT_STATUS 0x220 +#define HSDMA_REG_INT_MASK 0x228 +#define HSDMA_REG_SCH_Q01 0x280 +#define HSDMA_REG_SCH_Q23 0x284 + +#define HSDMA_DESCS_MAX 0xfff +#define HSDMA_DESCS_NUM 8 +#define HSDMA_DESCS_MASK (HSDMA_DESCS_NUM - 1) +#define HSDMA_NEXT_DESC(x) (((x) + 1) & HSDMA_DESCS_MASK) + +/* HSDMA_REG_INFO */ +#define HSDMA_INFO_INDEX_MASK 0xf +#define HSDMA_INFO_INDEX_SHIFT 24 +#define HSDMA_INFO_BASE_MASK 0xff +#define HSDMA_INFO_BASE_SHIFT 16 +#define HSDMA_INFO_RX_MASK 0xff +#define HSDMA_INFO_RX_SHIFT 8 +#define HSDMA_INFO_TX_MASK 0xff +#define HSDMA_INFO_TX_SHIFT 0 + +/* HSDMA_REG_GLO_CFG */ +#define HSDMA_GLO_TX_2B_OFFSET BIT(31) +#define HSDMA_GLO_CLK_GATE BIT(30) +#define HSDMA_GLO_BYTE_SWAP BIT(29) +#define HSDMA_GLO_MULTI_DMA BIT(10) +#define HSDMA_GLO_TWO_BUF BIT(9) +#define HSDMA_GLO_32B_DESC BIT(8) +#define HSDMA_GLO_BIG_ENDIAN BIT(7) +#define HSDMA_GLO_TX_DONE BIT(6) +#define HSDMA_GLO_BT_MASK 0x3 +#define HSDMA_GLO_BT_SHIFT 4 +#define HSDMA_GLO_RX_BUSY BIT(3) +#define HSDMA_GLO_RX_DMA BIT(2) +#define HSDMA_GLO_TX_BUSY BIT(1) +#define HSDMA_GLO_TX_DMA BIT(0) + +#define HSDMA_BT_SIZE_16BYTES (0 << HSDMA_GLO_BT_SHIFT) +#define HSDMA_BT_SIZE_32BYTES (1 << HSDMA_GLO_BT_SHIFT) +#define HSDMA_BT_SIZE_64BYTES (2 << HSDMA_GLO_BT_SHIFT) +#define HSDMA_BT_SIZE_128BYTES (3 << HSDMA_GLO_BT_SHIFT) + +#define HSDMA_GLO_DEFAULT (HSDMA_GLO_MULTI_DMA | \ + HSDMA_GLO_RX_DMA | HSDMA_GLO_TX_DMA | HSDMA_BT_SIZE_32BYTES) + +/* HSDMA_REG_RST_CFG */ +#define HSDMA_RST_RX_SHIFT 16 +#define HSDMA_RST_TX_SHIFT 0 + +/* HSDMA_REG_DELAY_INT */ +#define HSDMA_DELAY_INT_EN BIT(15) +#define HSDMA_DELAY_PEND_OFFSET 8 +#define HSDMA_DELAY_TIME_OFFSET 0 +#define HSDMA_DELAY_TX_OFFSET 16 +#define HSDMA_DELAY_RX_OFFSET 0 + +#define HSDMA_DELAY_INIT(x) (HSDMA_DELAY_INT_EN | \ + ((x) << HSDMA_DELAY_PEND_OFFSET)) +#define HSDMA_DELAY(x) ((HSDMA_DELAY_INIT(x) << \ + HSDMA_DELAY_TX_OFFSET) | HSDMA_DELAY_INIT(x)) + +/* HSDMA_REG_INT_STATUS */ +#define HSDMA_INT_DELAY_RX_COH BIT(31) +#define HSDMA_INT_DELAY_RX_INT BIT(30) +#define HSDMA_INT_DELAY_TX_COH BIT(29) +#define HSDMA_INT_DELAY_TX_INT BIT(28) +#define HSDMA_INT_RX_MASK 0x3 +#define HSDMA_INT_RX_SHIFT 16 +#define HSDMA_INT_RX_Q0 BIT(16) +#define HSDMA_INT_TX_MASK 0xf +#define HSDMA_INT_TX_SHIFT 0 +#define HSDMA_INT_TX_Q0 BIT(0) + +/* tx/rx dma desc flags */ +#define HSDMA_PLEN_MASK 0x3fff +#define HSDMA_DESC_DONE BIT(31) +#define HSDMA_DESC_LS0 BIT(30) +#define HSDMA_DESC_PLEN0(_x) (((_x) & HSDMA_PLEN_MASK) << 16) +#define HSDMA_DESC_TAG BIT(15) +#define HSDMA_DESC_LS1 BIT(14) +#define HSDMA_DESC_PLEN1(_x) ((_x) & HSDMA_PLEN_MASK) + +/* align 4 bytes */ +#define HSDMA_ALIGN_SIZE 3 +/* align size 128bytes */ +#define HSDMA_MAX_PLEN 0x3f80 + +struct hsdma_desc { + u32 addr0; + u32 flags; + u32 addr1; + u32 unused; +}; + +struct mtk_hsdma_sg { + dma_addr_t src_addr; + dma_addr_t dst_addr; + u32 len; +}; + +struct mtk_hsdma_desc { + struct virt_dma_desc vdesc; + unsigned int num_sgs; + struct mtk_hsdma_sg sg[1]; +}; + +struct mtk_hsdma_chan { + struct virt_dma_chan vchan; + unsigned int id; + dma_addr_t desc_addr; + int tx_idx; + int rx_idx; + struct hsdma_desc *tx_ring; + struct hsdma_desc *rx_ring; + struct mtk_hsdma_desc *desc; + unsigned int next_sg; +}; + +struct mtk_hsdam_engine { + struct dma_device ddev; + struct device_dma_parameters dma_parms; + void __iomem *base; + struct tasklet_struct task; + volatile unsigned long chan_issued; + + struct mtk_hsdma_chan chan[1]; +}; + +static inline struct mtk_hsdam_engine *mtk_hsdma_chan_get_dev( + struct mtk_hsdma_chan *chan) +{ + return container_of(chan->vchan.chan.device, struct mtk_hsdam_engine, + ddev); +} + +static inline struct mtk_hsdma_chan *to_mtk_hsdma_chan(struct dma_chan *c) +{ + return container_of(c, struct mtk_hsdma_chan, vchan.chan); +} + +static inline struct mtk_hsdma_desc *to_mtk_hsdma_desc( + struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct mtk_hsdma_desc, vdesc); +} + +static inline u32 mtk_hsdma_read(struct mtk_hsdam_engine *hsdma, u32 reg) +{ + return readl(hsdma->base + reg); +} + +static inline void mtk_hsdma_write(struct mtk_hsdam_engine *hsdma, + unsigned reg, u32 val) +{ + writel(val, hsdma->base + reg); +} + +static void mtk_hsdma_reset_chan(struct mtk_hsdam_engine *hsdma, + struct mtk_hsdma_chan *chan) +{ + chan->tx_idx = 0; + chan->rx_idx = HSDMA_DESCS_NUM - 1; + + mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx); + mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx); + + mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG, + 0x1 << (chan->id + HSDMA_RST_TX_SHIFT)); + mtk_hsdma_write(hsdma, HSDMA_REG_RST_CFG, + 0x1 << (chan->id + HSDMA_RST_RX_SHIFT)); +} + +static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma) +{ + dev_dbg(hsdma->ddev.dev, "tbase %08x, tcnt %08x, " \ + "tctx %08x, tdtx: %08x, rbase %08x, " \ + "rcnt %08x, rctx %08x, rdtx %08x\n", + mtk_hsdma_read(hsdma, HSDMA_REG_TX_BASE), + mtk_hsdma_read(hsdma, HSDMA_REG_TX_CNT), + mtk_hsdma_read(hsdma, HSDMA_REG_TX_CTX), + mtk_hsdma_read(hsdma, HSDMA_REG_TX_DTX), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_BASE), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_CNT), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX)); + + dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, " \ + "intr_stat %08x, intr_mask %08x\n", + mtk_hsdma_read(hsdma, HSDMA_REG_INFO), + mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG), + mtk_hsdma_read(hsdma, HSDMA_REG_DELAY_INT), + mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS), + mtk_hsdma_read(hsdma, HSDMA_REG_INT_MASK)); +} + +static void hsdma_dump_desc(struct mtk_hsdam_engine *hsdma, + struct mtk_hsdma_chan *chan) +{ + struct hsdma_desc *tx_desc; + struct hsdma_desc *rx_desc; + int i; + + dev_dbg(hsdma->ddev.dev, "tx idx: %d, rx idx: %d\n", + chan->tx_idx, chan->rx_idx); + + for (i = 0; i < HSDMA_DESCS_NUM; i++) { + tx_desc = &chan->tx_ring[i]; + rx_desc = &chan->rx_ring[i]; + + dev_dbg(hsdma->ddev.dev, "%d tx addr0: %08x, flags %08x, " \ + "tx addr1: %08x, rx addr0 %08x, flags %08x\n", + i, tx_desc->addr0, tx_desc->flags, \ + tx_desc->addr1, rx_desc->addr0, rx_desc->flags); + } +} + +static void mtk_hsdma_reset(struct mtk_hsdam_engine *hsdma, + struct mtk_hsdma_chan *chan) +{ + int i; + + /* disable dma */ + mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0); + + /* disable intr */ + mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0); + + /* init desc value */ + for (i = 0; i < HSDMA_DESCS_NUM; i++) { + chan->tx_ring[i].addr0 = 0; + chan->tx_ring[i].flags = HSDMA_DESC_LS0 | + HSDMA_DESC_DONE; + } + for (i = 0; i < HSDMA_DESCS_NUM; i++) { + chan->rx_ring[i].addr0 = 0; + chan->rx_ring[i].flags = 0; + } + + /* reset */ + mtk_hsdma_reset_chan(hsdma, chan); + + /* enable intr */ + mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0); + + /* enable dma */ + mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT); +} + +static int mtk_hsdma_terminate_all(struct dma_chan *c) +{ + struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); + struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan); + unsigned long timeout; + LIST_HEAD(head); + + spin_lock_bh(&chan->vchan.lock); + chan->desc = NULL; + clear_bit(chan->id, &hsdma->chan_issued); + vchan_get_all_descriptors(&chan->vchan, &head); + spin_unlock_bh(&chan->vchan.lock); + + vchan_dma_desc_free_list(&chan->vchan, &head); + + /* wait dma transfer complete */ + timeout = jiffies + msecs_to_jiffies(2000); + while (mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG) & + (HSDMA_GLO_RX_BUSY | HSDMA_GLO_TX_BUSY)) { + if (time_after_eq(jiffies, timeout)) { + hsdma_dump_desc(hsdma, chan); + mtk_hsdma_reset(hsdma, chan); + dev_err(hsdma->ddev.dev, "timeout, reset it\n"); + break; + } + cpu_relax(); + } + + return 0; +} + +static int mtk_hsdma_start_transfer(struct mtk_hsdam_engine *hsdma, + struct mtk_hsdma_chan *chan) +{ + dma_addr_t src, dst; + size_t len, tlen; + struct hsdma_desc *tx_desc, *rx_desc; + struct mtk_hsdma_sg *sg; + unsigned int i; + int rx_idx; + + sg = &chan->desc->sg[0]; + len = sg->len; + chan->desc->num_sgs = DIV_ROUND_UP(len, HSDMA_MAX_PLEN); + + /* tx desc */ + src = sg->src_addr; + for (i = 0; i < chan->desc->num_sgs; i++) { + if (len > HSDMA_MAX_PLEN) + tlen = HSDMA_MAX_PLEN; + else + tlen = len; + + if (i & 0x1) { + tx_desc->addr1 = src; + tx_desc->flags |= HSDMA_DESC_PLEN1(tlen); + } else { + tx_desc = &chan->tx_ring[chan->tx_idx]; + tx_desc->addr0 = src; + tx_desc->flags = HSDMA_DESC_PLEN0(tlen); + + /* update index */ + chan->tx_idx = HSDMA_NEXT_DESC(chan->tx_idx); + } + + src += tlen; + len -= tlen; + } + if (i & 0x1) + tx_desc->flags |= HSDMA_DESC_LS0; + else + tx_desc->flags |= HSDMA_DESC_LS1; + + /* rx desc */ + rx_idx = HSDMA_NEXT_DESC(chan->rx_idx); + len = sg->len; + dst = sg->dst_addr; + for (i = 0; i < chan->desc->num_sgs; i++) { + rx_desc = &chan->rx_ring[rx_idx]; + if (len > HSDMA_MAX_PLEN) + tlen = HSDMA_MAX_PLEN; + else + tlen = len; + + rx_desc->addr0 = dst; + rx_desc->flags = HSDMA_DESC_PLEN0(tlen); + + dst += tlen; + len -= tlen; + + /* update index */ + rx_idx = HSDMA_NEXT_DESC(rx_idx); + } + + /* make sure desc and index all up to date */ + wmb(); + mtk_hsdma_write(hsdma, HSDMA_REG_TX_CTX, chan->tx_idx); + + return 0; +} + +static int gdma_next_desc(struct mtk_hsdma_chan *chan) +{ + struct virt_dma_desc *vdesc; + + vdesc = vchan_next_desc(&chan->vchan); + if (!vdesc) { + chan->desc = NULL; + return 0; + } + chan->desc = to_mtk_hsdma_desc(vdesc); + chan->next_sg = 0; + + return 1; +} + +static void mtk_hsdma_chan_done(struct mtk_hsdam_engine *hsdma, + struct mtk_hsdma_chan *chan) +{ + struct mtk_hsdma_desc *desc; + int chan_issued; + + chan_issued = 0; + spin_lock_bh(&chan->vchan.lock); + desc = chan->desc; + if (likely(desc)) { + if (chan->next_sg == desc->num_sgs) { + list_del(&desc->vdesc.node); + vchan_cookie_complete(&desc->vdesc); + chan_issued = gdma_next_desc(chan); + } + } else + dev_dbg(hsdma->ddev.dev, "no desc to complete\n"); + + if (chan_issued) + set_bit(chan->id, &hsdma->chan_issued); + spin_unlock_bh(&chan->vchan.lock); +} + +static irqreturn_t mtk_hsdma_irq(int irq, void *devid) +{ + struct mtk_hsdam_engine *hsdma = devid; + u32 status; + + status = mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS); + if (unlikely(!status)) + return IRQ_NONE; + + if (likely(status & HSDMA_INT_RX_Q0)) + tasklet_schedule(&hsdma->task); + else + dev_dbg(hsdma->ddev.dev, "unhandle irq status %08x\n", + status); + /* clean intr bits */ + mtk_hsdma_write(hsdma, HSDMA_REG_INT_STATUS, status); + + return IRQ_HANDLED; +} + +static void mtk_hsdma_issue_pending(struct dma_chan *c) +{ + struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); + struct mtk_hsdam_engine *hsdma = mtk_hsdma_chan_get_dev(chan); + + spin_lock_bh(&chan->vchan.lock); + if (vchan_issue_pending(&chan->vchan) && !chan->desc) { + if (gdma_next_desc(chan)) { + set_bit(chan->id, &hsdma->chan_issued); + tasklet_schedule(&hsdma->task); + } else + dev_dbg(hsdma->ddev.dev, "no desc to issue\n"); + } + spin_unlock_bh(&chan->vchan.lock); +} + +static struct dma_async_tx_descriptor *mtk_hsdma_prep_dma_memcpy( + struct dma_chan *c, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct mtk_hsdma_chan *chan = to_mtk_hsdma_chan(c); + struct mtk_hsdma_desc *desc; + + if (len <= 0) + return NULL; + + desc = kzalloc(sizeof(struct mtk_hsdma_desc), GFP_ATOMIC); + if (!desc) { + dev_err(c->device->dev, "alloc memcpy decs error\n"); + return NULL; + } + + desc->sg[0].src_addr = src; + desc->sg[0].dst_addr = dest; + desc->sg[0].len = len; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + +static enum dma_status mtk_hsdma_tx_status(struct dma_chan *c, + dma_cookie_t cookie, + struct dma_tx_state *state) +{ + return dma_cookie_status(c, cookie, state); +} + +static void mtk_hsdma_free_chan_resources(struct dma_chan *c) +{ + vchan_free_chan_resources(to_virt_chan(c)); +} + +static void mtk_hsdma_desc_free(struct virt_dma_desc *vdesc) +{ + kfree(container_of(vdesc, struct mtk_hsdma_desc, vdesc)); +} + +static void mtk_hsdma_tx(struct mtk_hsdam_engine *hsdma) +{ + struct mtk_hsdma_chan *chan; + + if (test_and_clear_bit(0, &hsdma->chan_issued)) { + chan = &hsdma->chan[0]; + if (chan->desc) + mtk_hsdma_start_transfer(hsdma, chan); + else + dev_dbg(hsdma->ddev.dev, "chan 0 no desc to issue\n"); + } +} + +static void mtk_hsdma_rx(struct mtk_hsdam_engine *hsdma) +{ + struct mtk_hsdma_chan *chan; + int next_idx, drx_idx, cnt; + + chan = &hsdma->chan[0]; + next_idx = HSDMA_NEXT_DESC(chan->rx_idx); + drx_idx = mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX); + + cnt = (drx_idx - next_idx) & HSDMA_DESCS_MASK; + if (!cnt) + return; + + chan->next_sg += cnt; + chan->rx_idx = (chan->rx_idx + cnt) & HSDMA_DESCS_MASK; + + /* update rx crx */ + wmb(); + mtk_hsdma_write(hsdma, HSDMA_REG_RX_CRX, chan->rx_idx); + + mtk_hsdma_chan_done(hsdma, chan); +} + +static void mtk_hsdma_tasklet(unsigned long arg) +{ + struct mtk_hsdam_engine *hsdma = (struct mtk_hsdam_engine *)arg; + + mtk_hsdma_rx(hsdma); + mtk_hsdma_tx(hsdma); +} + +static int mtk_hsdam_alloc_desc(struct mtk_hsdam_engine *hsdma, + struct mtk_hsdma_chan *chan) +{ + int i; + + chan->tx_ring = dma_alloc_coherent(hsdma->ddev.dev, + 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), + &chan->desc_addr, GFP_ATOMIC | __GFP_ZERO); + if (!chan->tx_ring) + goto no_mem; + + chan->rx_ring = &chan->tx_ring[HSDMA_DESCS_NUM]; + + /* init tx ring value */ + for (i = 0; i < HSDMA_DESCS_NUM; i++) + chan->tx_ring[i].flags = HSDMA_DESC_LS0 | HSDMA_DESC_DONE; + + return 0; +no_mem: + return -ENOMEM; +} + +static void mtk_hsdam_free_desc(struct mtk_hsdam_engine *hsdma, + struct mtk_hsdma_chan *chan) +{ + if (chan->tx_ring) { + dma_free_coherent(hsdma->ddev.dev, + 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), + chan->tx_ring, chan->desc_addr); + chan->tx_ring = NULL; + chan->rx_ring = NULL; + } +} + +static int mtk_hsdma_init(struct mtk_hsdam_engine *hsdma) +{ + struct mtk_hsdma_chan *chan; + int ret; + u32 reg; + + /* init desc */ + chan = &hsdma->chan[0]; + ret = mtk_hsdam_alloc_desc(hsdma, chan); + if (ret) + return ret; + + /* tx */ + mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, chan->desc_addr); + mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, HSDMA_DESCS_NUM); + /* rx */ + mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, chan->desc_addr + + (sizeof(struct hsdma_desc) * HSDMA_DESCS_NUM)); + mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, HSDMA_DESCS_NUM); + /* reset */ + mtk_hsdma_reset_chan(hsdma, chan); + + /* enable rx intr */ + mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, HSDMA_INT_RX_Q0); + + /* enable dma */ + mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, HSDMA_GLO_DEFAULT); + + /* hardware info */ + reg = mtk_hsdma_read(hsdma, HSDMA_REG_INFO); + dev_info(hsdma->ddev.dev, "rx: %d, tx: %d\n", + (reg >> HSDMA_INFO_RX_SHIFT) & HSDMA_INFO_RX_MASK, + (reg >> HSDMA_INFO_TX_SHIFT) & HSDMA_INFO_TX_MASK); + + hsdma_dump_reg(hsdma); + + return ret; +} + +static void mtk_hsdma_uninit(struct mtk_hsdam_engine *hsdma) +{ + struct mtk_hsdma_chan *chan; + + /* disable dma */ + mtk_hsdma_write(hsdma, HSDMA_REG_GLO_CFG, 0); + + /* disable intr */ + mtk_hsdma_write(hsdma, HSDMA_REG_INT_MASK, 0); + + /* free desc */ + chan = &hsdma->chan[0]; + mtk_hsdam_free_desc(hsdma, chan); + + /* tx */ + mtk_hsdma_write(hsdma, HSDMA_REG_TX_BASE, 0); + mtk_hsdma_write(hsdma, HSDMA_REG_TX_CNT, 0); + /* rx */ + mtk_hsdma_write(hsdma, HSDMA_REG_RX_BASE, 0); + mtk_hsdma_write(hsdma, HSDMA_REG_RX_CNT, 0); + /* reset */ + mtk_hsdma_reset_chan(hsdma, chan); +} + +static const struct of_device_id mtk_hsdma_of_match[] = { + { .compatible = "mediatek,mt7621-hsdma" }, + { }, +}; + +static int mtk_hsdma_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct mtk_hsdma_chan *chan; + struct mtk_hsdam_engine *hsdma; + struct dma_device *dd; + struct resource *res; + int ret; + int irq; + void __iomem *base; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + match = of_match_device(mtk_hsdma_of_match, &pdev->dev); + if (!match) + return -EINVAL; + + hsdma = devm_kzalloc(&pdev->dev, sizeof(*hsdma), GFP_KERNEL); + if (!hsdma) { + dev_err(&pdev->dev, "alloc dma device failed\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + hsdma->base = base + HSDMA_BASE_OFFSET; + tasklet_init(&hsdma->task, mtk_hsdma_tasklet, (unsigned long)hsdma); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + return -EINVAL; + } + ret = devm_request_irq(&pdev->dev, irq, mtk_hsdma_irq, + 0, dev_name(&pdev->dev), hsdma); + if (ret) { + dev_err(&pdev->dev, "failed to request irq\n"); + return ret; + } + + device_reset(&pdev->dev); + + dd = &hsdma->ddev; + dma_cap_set(DMA_MEMCPY, dd->cap_mask); + dd->copy_align = HSDMA_ALIGN_SIZE; + dd->device_free_chan_resources = mtk_hsdma_free_chan_resources; + dd->device_prep_dma_memcpy = mtk_hsdma_prep_dma_memcpy; + dd->device_terminate_all = mtk_hsdma_terminate_all; + dd->device_tx_status = mtk_hsdma_tx_status; + dd->device_issue_pending = mtk_hsdma_issue_pending; + dd->dev = &pdev->dev; + dd->dev->dma_parms = &hsdma->dma_parms; + dma_set_max_seg_size(dd->dev, HSDMA_MAX_PLEN); + INIT_LIST_HEAD(&dd->channels); + + chan = &hsdma->chan[0]; + chan->id = 0; + chan->vchan.desc_free = mtk_hsdma_desc_free; + vchan_init(&chan->vchan, dd); + + /* init hardware */ + ret = mtk_hsdma_init(hsdma); + if (ret) { + dev_err(&pdev->dev, "failed to alloc ring descs\n"); + return ret; + } + + ret = dma_async_device_register(dd); + if (ret) { + dev_err(&pdev->dev, "failed to register dma device\n"); + return ret; + } + + ret = of_dma_controller_register(pdev->dev.of_node, + of_dma_xlate_by_chan_id, hsdma); + if (ret) { + dev_err(&pdev->dev, "failed to register of dma controller\n"); + goto err_unregister; + } + + platform_set_drvdata(pdev, hsdma); + + return 0; + +err_unregister: + dma_async_device_unregister(dd); + return ret; +} + +static int mtk_hsdma_remove(struct platform_device *pdev) +{ + struct mtk_hsdam_engine *hsdma = platform_get_drvdata(pdev); + + mtk_hsdma_uninit(hsdma); + + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&hsdma->ddev); + + return 0; +} + +static struct platform_driver mtk_hsdma_driver = { + .probe = mtk_hsdma_probe, + .remove = mtk_hsdma_remove, + .driver = { + .name = "hsdma-mt7621", + .of_match_table = mtk_hsdma_of_match, + }, +}; +module_platform_driver(mtk_hsdma_driver); + +MODULE_AUTHOR("Michael Lee <igvtee@gmail.com>"); +MODULE_DESCRIPTION("MTK HSDMA driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/mt7621-dma/ralink-gdma.c b/drivers/staging/mt7621-dma/ralink-gdma.c new file mode 100644 index 000000000000..6d9fe175ea52 --- /dev/null +++ b/drivers/staging/mt7621-dma/ralink-gdma.c @@ -0,0 +1,930 @@ +/* + * Copyright (C) 2013, Lars-Peter Clausen <lars@metafoo.de> + * GDMA4740 DMAC support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/irq.h> +#include <linux/of_dma.h> +#include <linux/reset.h> +#include <linux/of_device.h> + +#include "virt-dma.h" + +#define GDMA_REG_SRC_ADDR(x) (0x00 + (x) * 0x10) +#define GDMA_REG_DST_ADDR(x) (0x04 + (x) * 0x10) + +#define GDMA_REG_CTRL0(x) (0x08 + (x) * 0x10) +#define GDMA_REG_CTRL0_TX_MASK 0xffff +#define GDMA_REG_CTRL0_TX_SHIFT 16 +#define GDMA_REG_CTRL0_CURR_MASK 0xff +#define GDMA_REG_CTRL0_CURR_SHIFT 8 +#define GDMA_REG_CTRL0_SRC_ADDR_FIXED BIT(7) +#define GDMA_REG_CTRL0_DST_ADDR_FIXED BIT(6) +#define GDMA_REG_CTRL0_BURST_MASK 0x7 +#define GDMA_REG_CTRL0_BURST_SHIFT 3 +#define GDMA_REG_CTRL0_DONE_INT BIT(2) +#define GDMA_REG_CTRL0_ENABLE BIT(1) +#define GDMA_REG_CTRL0_SW_MODE BIT(0) + +#define GDMA_REG_CTRL1(x) (0x0c + (x) * 0x10) +#define GDMA_REG_CTRL1_SEG_MASK 0xf +#define GDMA_REG_CTRL1_SEG_SHIFT 22 +#define GDMA_REG_CTRL1_REQ_MASK 0x3f +#define GDMA_REG_CTRL1_SRC_REQ_SHIFT 16 +#define GDMA_REG_CTRL1_DST_REQ_SHIFT 8 +#define GDMA_REG_CTRL1_CONTINOUS BIT(14) +#define GDMA_REG_CTRL1_NEXT_MASK 0x1f +#define GDMA_REG_CTRL1_NEXT_SHIFT 3 +#define GDMA_REG_CTRL1_COHERENT BIT(2) +#define GDMA_REG_CTRL1_FAIL BIT(1) +#define GDMA_REG_CTRL1_MASK BIT(0) + +#define GDMA_REG_UNMASK_INT 0x200 +#define GDMA_REG_DONE_INT 0x204 + +#define GDMA_REG_GCT 0x220 +#define GDMA_REG_GCT_CHAN_MASK 0x3 +#define GDMA_REG_GCT_CHAN_SHIFT 3 +#define GDMA_REG_GCT_VER_MASK 0x3 +#define GDMA_REG_GCT_VER_SHIFT 1 +#define GDMA_REG_GCT_ARBIT_RR BIT(0) + +#define GDMA_REG_REQSTS 0x2a0 +#define GDMA_REG_ACKSTS 0x2a4 +#define GDMA_REG_FINSTS 0x2a8 + +/* for RT305X gdma registers */ +#define GDMA_RT305X_CTRL0_REQ_MASK 0xf +#define GDMA_RT305X_CTRL0_SRC_REQ_SHIFT 12 +#define GDMA_RT305X_CTRL0_DST_REQ_SHIFT 8 + +#define GDMA_RT305X_CTRL1_FAIL BIT(4) +#define GDMA_RT305X_CTRL1_NEXT_MASK 0x7 +#define GDMA_RT305X_CTRL1_NEXT_SHIFT 1 + +#define GDMA_RT305X_STATUS_INT 0x80 +#define GDMA_RT305X_STATUS_SIGNAL 0x84 +#define GDMA_RT305X_GCT 0x88 + +/* for MT7621 gdma registers */ +#define GDMA_REG_PERF_START(x) (0x230 + (x) * 0x8) +#define GDMA_REG_PERF_END(x) (0x234 + (x) * 0x8) + +enum gdma_dma_transfer_size { + GDMA_TRANSFER_SIZE_4BYTE = 0, + GDMA_TRANSFER_SIZE_8BYTE = 1, + GDMA_TRANSFER_SIZE_16BYTE = 2, + GDMA_TRANSFER_SIZE_32BYTE = 3, + GDMA_TRANSFER_SIZE_64BYTE = 4, +}; + +struct gdma_dma_sg { + dma_addr_t src_addr; + dma_addr_t dst_addr; + u32 len; +}; + +struct gdma_dma_desc { + struct virt_dma_desc vdesc; + + enum dma_transfer_direction direction; + bool cyclic; + + u32 residue; + unsigned int num_sgs; + struct gdma_dma_sg sg[]; +}; + +struct gdma_dmaengine_chan { + struct virt_dma_chan vchan; + unsigned int id; + unsigned int slave_id; + + dma_addr_t fifo_addr; + enum gdma_dma_transfer_size burst_size; + + struct gdma_dma_desc *desc; + unsigned int next_sg; +}; + +struct gdma_dma_dev { + struct dma_device ddev; + struct device_dma_parameters dma_parms; + struct gdma_data *data; + void __iomem *base; + struct tasklet_struct task; + volatile unsigned long chan_issued; + atomic_t cnt; + + struct gdma_dmaengine_chan chan[]; +}; + +struct gdma_data { + int chancnt; + u32 done_int_reg; + void (*init)(struct gdma_dma_dev *dma_dev); + int (*start_transfer)(struct gdma_dmaengine_chan *chan); +}; + +static struct gdma_dma_dev *gdma_dma_chan_get_dev( + struct gdma_dmaengine_chan *chan) +{ + return container_of(chan->vchan.chan.device, struct gdma_dma_dev, + ddev); +} + +static struct gdma_dmaengine_chan *to_gdma_dma_chan(struct dma_chan *c) +{ + return container_of(c, struct gdma_dmaengine_chan, vchan.chan); +} + +static struct gdma_dma_desc *to_gdma_dma_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct gdma_dma_desc, vdesc); +} + +static inline uint32_t gdma_dma_read(struct gdma_dma_dev *dma_dev, + unsigned int reg) +{ + return readl(dma_dev->base + reg); +} + +static inline void gdma_dma_write(struct gdma_dma_dev *dma_dev, + unsigned reg, uint32_t val) +{ + writel(val, dma_dev->base + reg); +} + +static struct gdma_dma_desc *gdma_dma_alloc_desc(unsigned int num_sgs) +{ + return kzalloc(sizeof(struct gdma_dma_desc) + + sizeof(struct gdma_dma_sg) * num_sgs, GFP_ATOMIC); +} + +static enum gdma_dma_transfer_size gdma_dma_maxburst(u32 maxburst) +{ + if (maxburst < 2) + return GDMA_TRANSFER_SIZE_4BYTE; + else if (maxburst < 4) + return GDMA_TRANSFER_SIZE_8BYTE; + else if (maxburst < 8) + return GDMA_TRANSFER_SIZE_16BYTE; + else if (maxburst < 16) + return GDMA_TRANSFER_SIZE_32BYTE; + else + return GDMA_TRANSFER_SIZE_64BYTE; +} + +static int gdma_dma_config(struct dma_chan *c, + struct dma_slave_config *config) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + + if (config->device_fc) { + dev_err(dma_dev->ddev.dev, "not support flow controller\n"); + return -EINVAL; + } + + switch (config->direction) { + case DMA_MEM_TO_DEV: + if (config->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { + dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); + return -EINVAL; + } + chan->slave_id = config->slave_id; + chan->fifo_addr = config->dst_addr; + chan->burst_size = gdma_dma_maxburst(config->dst_maxburst); + break; + case DMA_DEV_TO_MEM: + if (config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) { + dev_err(dma_dev->ddev.dev, "only support 4 byte buswidth\n"); + return -EINVAL; + } + chan->slave_id = config->slave_id; + chan->fifo_addr = config->src_addr; + chan->burst_size = gdma_dma_maxburst(config->src_maxburst); + break; + default: + dev_err(dma_dev->ddev.dev, "direction type %d error\n", + config->direction); + return -EINVAL; + } + + return 0; +} + +static int gdma_dma_terminate_all(struct dma_chan *c) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + unsigned long flags, timeout; + LIST_HEAD(head); + int i = 0; + + spin_lock_irqsave(&chan->vchan.lock, flags); + chan->desc = NULL; + clear_bit(chan->id, &dma_dev->chan_issued); + vchan_get_all_descriptors(&chan->vchan, &head); + spin_unlock_irqrestore(&chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&chan->vchan, &head); + + /* wait dma transfer complete */ + timeout = jiffies + msecs_to_jiffies(5000); + while (gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)) & + GDMA_REG_CTRL0_ENABLE) { + if (time_after_eq(jiffies, timeout)) { + dev_err(dma_dev->ddev.dev, "chan %d wait timeout\n", + chan->id); + /* restore to init value */ + gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), 0); + break; + } + cpu_relax(); + i++; + } + + if (i) + dev_dbg(dma_dev->ddev.dev, "terminate chan %d loops %d\n", + chan->id, i); + + return 0; +} + +static void rt305x_dump_reg(struct gdma_dma_dev *dma_dev, int id) +{ + dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ + "ctr1 %08x, intr %08x, signal %08x\n", id, + gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), + gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_INT), + gdma_dma_read(dma_dev, GDMA_RT305X_STATUS_SIGNAL)); +} + +static int rt305x_gdma_start_transfer(struct gdma_dmaengine_chan *chan) +{ + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + dma_addr_t src_addr, dst_addr; + struct gdma_dma_sg *sg; + uint32_t ctrl0, ctrl1; + + /* verify chan is already stopped */ + ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); + if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { + dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", + chan->id, ctrl0); + rt305x_dump_reg(dma_dev, chan->id); + return -EINVAL; + } + + sg = &chan->desc->sg[chan->next_sg]; + if (chan->desc->direction == DMA_MEM_TO_DEV) { + src_addr = sg->src_addr; + dst_addr = chan->fifo_addr; + ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED | \ + (8 << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ + (chan->slave_id << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); + } else if (chan->desc->direction == DMA_DEV_TO_MEM) { + src_addr = chan->fifo_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED | \ + (chan->slave_id << GDMA_RT305X_CTRL0_SRC_REQ_SHIFT) | \ + (8 << GDMA_RT305X_CTRL0_DST_REQ_SHIFT); + } else if (chan->desc->direction == DMA_MEM_TO_MEM) { + /* + * TODO: memcpy function have bugs. sometime it will copy + * more 8 bytes data when using dmatest verify. + */ + src_addr = sg->src_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SW_MODE | \ + (8 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (8 << GDMA_REG_CTRL1_DST_REQ_SHIFT); + } else { + dev_err(dma_dev->ddev.dev, "direction type %d error\n", + chan->desc->direction); + return -EINVAL; + } + + ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ + (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ + GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; + ctrl1 = chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; + + chan->next_sg++; + gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); + gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); + gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); + + /* make sure next_sg is update */ + wmb(); + gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); + + return 0; +} + +static void rt3883_dump_reg(struct gdma_dma_dev *dma_dev, int id) +{ + dev_dbg(dma_dev->ddev.dev, "chan %d, src %08x, dst %08x, ctr0 %08x, " \ + "ctr1 %08x, unmask %08x, done %08x, " \ + "req %08x, ack %08x, fin %08x\n", id, + gdma_dma_read(dma_dev, GDMA_REG_SRC_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_DST_ADDR(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL0(id)), + gdma_dma_read(dma_dev, GDMA_REG_CTRL1(id)), + gdma_dma_read(dma_dev, GDMA_REG_UNMASK_INT), + gdma_dma_read(dma_dev, GDMA_REG_DONE_INT), + gdma_dma_read(dma_dev, GDMA_REG_REQSTS), + gdma_dma_read(dma_dev, GDMA_REG_ACKSTS), + gdma_dma_read(dma_dev, GDMA_REG_FINSTS)); +} + +static int rt3883_gdma_start_transfer(struct gdma_dmaengine_chan *chan) +{ + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + dma_addr_t src_addr, dst_addr; + struct gdma_dma_sg *sg; + uint32_t ctrl0, ctrl1; + + /* verify chan is already stopped */ + ctrl0 = gdma_dma_read(dma_dev, GDMA_REG_CTRL0(chan->id)); + if (unlikely(ctrl0 & GDMA_REG_CTRL0_ENABLE)) { + dev_err(dma_dev->ddev.dev, "chan %d is start(%08x).\n", + chan->id, ctrl0); + rt3883_dump_reg(dma_dev, chan->id); + return -EINVAL; + } + + sg = &chan->desc->sg[chan->next_sg]; + if (chan->desc->direction == DMA_MEM_TO_DEV) { + src_addr = sg->src_addr; + dst_addr = chan->fifo_addr; + ctrl0 = GDMA_REG_CTRL0_DST_ADDR_FIXED; + ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (chan->slave_id << GDMA_REG_CTRL1_DST_REQ_SHIFT); + } else if (chan->desc->direction == DMA_DEV_TO_MEM) { + src_addr = chan->fifo_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SRC_ADDR_FIXED; + ctrl1 = (chan->slave_id << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ + GDMA_REG_CTRL1_COHERENT; + } else if (chan->desc->direction == DMA_MEM_TO_MEM) { + src_addr = sg->src_addr; + dst_addr = sg->dst_addr; + ctrl0 = GDMA_REG_CTRL0_SW_MODE; + ctrl1 = (32 << GDMA_REG_CTRL1_SRC_REQ_SHIFT) | \ + (32 << GDMA_REG_CTRL1_DST_REQ_SHIFT) | \ + GDMA_REG_CTRL1_COHERENT; + } else { + dev_err(dma_dev->ddev.dev, "direction type %d error\n", + chan->desc->direction); + return -EINVAL; + } + + ctrl0 |= (sg->len << GDMA_REG_CTRL0_TX_SHIFT) | \ + (chan->burst_size << GDMA_REG_CTRL0_BURST_SHIFT) | \ + GDMA_REG_CTRL0_DONE_INT | GDMA_REG_CTRL0_ENABLE; + ctrl1 |= chan->id << GDMA_REG_CTRL1_NEXT_SHIFT; + + chan->next_sg++; + gdma_dma_write(dma_dev, GDMA_REG_SRC_ADDR(chan->id), src_addr); + gdma_dma_write(dma_dev, GDMA_REG_DST_ADDR(chan->id), dst_addr); + gdma_dma_write(dma_dev, GDMA_REG_CTRL1(chan->id), ctrl1); + + /* make sure next_sg is update */ + wmb(); + gdma_dma_write(dma_dev, GDMA_REG_CTRL0(chan->id), ctrl0); + + return 0; +} + +static inline int gdma_start_transfer(struct gdma_dma_dev *dma_dev, + struct gdma_dmaengine_chan *chan) +{ + return dma_dev->data->start_transfer(chan); +} + +static int gdma_next_desc(struct gdma_dmaengine_chan *chan) +{ + struct virt_dma_desc *vdesc; + + vdesc = vchan_next_desc(&chan->vchan); + if (!vdesc) { + chan->desc = NULL; + return 0; + } + chan->desc = to_gdma_dma_desc(vdesc); + chan->next_sg = 0; + + return 1; +} + +static void gdma_dma_chan_irq(struct gdma_dma_dev *dma_dev, + struct gdma_dmaengine_chan *chan) +{ + struct gdma_dma_desc *desc; + unsigned long flags; + int chan_issued; + + chan_issued = 0; + spin_lock_irqsave(&chan->vchan.lock, flags); + desc = chan->desc; + if (desc) { + if (desc->cyclic) { + vchan_cyclic_callback(&desc->vdesc); + if (chan->next_sg == desc->num_sgs) + chan->next_sg = 0; + chan_issued = 1; + } else { + desc->residue -= desc->sg[chan->next_sg - 1].len; + if (chan->next_sg == desc->num_sgs) { + list_del(&desc->vdesc.node); + vchan_cookie_complete(&desc->vdesc); + chan_issued = gdma_next_desc(chan); + } else + chan_issued = 1; + } + } else + dev_dbg(dma_dev->ddev.dev, "chan %d no desc to complete\n", + chan->id); + if (chan_issued) + set_bit(chan->id, &dma_dev->chan_issued); + spin_unlock_irqrestore(&chan->vchan.lock, flags); +} + +static irqreturn_t gdma_dma_irq(int irq, void *devid) +{ + struct gdma_dma_dev *dma_dev = devid; + u32 done, done_reg; + unsigned int i; + + done_reg = dma_dev->data->done_int_reg; + done = gdma_dma_read(dma_dev, done_reg); + if (unlikely(!done)) + return IRQ_NONE; + + /* clean done bits */ + gdma_dma_write(dma_dev, done_reg, done); + + i = 0; + while (done) { + if (done & 0x1) { + gdma_dma_chan_irq(dma_dev, &dma_dev->chan[i]); + atomic_dec(&dma_dev->cnt); + } + done >>= 1; + i++; + } + + /* start only have work to do */ + if (dma_dev->chan_issued) + tasklet_schedule(&dma_dev->task); + + return IRQ_HANDLED; +} + +static void gdma_dma_issue_pending(struct dma_chan *c) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_dev *dma_dev = gdma_dma_chan_get_dev(chan); + unsigned long flags; + + spin_lock_irqsave(&chan->vchan.lock, flags); + if (vchan_issue_pending(&chan->vchan) && !chan->desc) { + if (gdma_next_desc(chan)) { + set_bit(chan->id, &dma_dev->chan_issued); + tasklet_schedule(&dma_dev->task); + } else + dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", + chan->id); + } + spin_unlock_irqrestore(&chan->vchan.lock, flags); +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_slave_sg( + struct dma_chan *c, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; + struct scatterlist *sg; + unsigned int i; + + desc = gdma_dma_alloc_desc(sg_len); + if (!desc) { + dev_err(c->device->dev, "alloc sg decs error\n"); + return NULL; + } + desc->residue = 0; + + for_each_sg(sgl, sg, sg_len, i) { + if (direction == DMA_MEM_TO_DEV) + desc->sg[i].src_addr = sg_dma_address(sg); + else if (direction == DMA_DEV_TO_MEM) + desc->sg[i].dst_addr = sg_dma_address(sg); + else { + dev_err(c->device->dev, "direction type %d error\n", + direction); + goto free_desc; + } + + if (unlikely(sg_dma_len(sg) > GDMA_REG_CTRL0_TX_MASK)) { + dev_err(c->device->dev, "sg len too large %d\n", + sg_dma_len(sg)); + goto free_desc; + } + desc->sg[i].len = sg_dma_len(sg); + desc->residue += sg_dma_len(sg); + } + + desc->num_sgs = sg_len; + desc->direction = direction; + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); + +free_desc: + kfree(desc); + return NULL; +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_dma_memcpy( + struct dma_chan *c, dma_addr_t dest, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; + unsigned int num_periods, i; + size_t xfer_count; + + if (len <= 0) + return NULL; + + chan->burst_size = gdma_dma_maxburst(len >> 2); + + xfer_count = GDMA_REG_CTRL0_TX_MASK; + num_periods = DIV_ROUND_UP(len, xfer_count); + + desc = gdma_dma_alloc_desc(num_periods); + if (!desc) { + dev_err(c->device->dev, "alloc memcpy decs error\n"); + return NULL; + } + desc->residue = len; + + for (i = 0; i < num_periods; i++) { + desc->sg[i].src_addr = src; + desc->sg[i].dst_addr = dest; + if (len > xfer_count) + desc->sg[i].len = xfer_count; + else + desc->sg[i].len = len; + src += desc->sg[i].len; + dest += desc->sg[i].len; + len -= desc->sg[i].len; + } + + desc->num_sgs = num_periods; + desc->direction = DMA_MEM_TO_MEM; + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + +static struct dma_async_tx_descriptor *gdma_dma_prep_dma_cyclic( + struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct gdma_dma_desc *desc; + unsigned int num_periods, i; + + if (buf_len % period_len) + return NULL; + + if (period_len > GDMA_REG_CTRL0_TX_MASK) { + dev_err(c->device->dev, "cyclic len too large %d\n", + period_len); + return NULL; + } + + num_periods = buf_len / period_len; + desc = gdma_dma_alloc_desc(num_periods); + if (!desc) { + dev_err(c->device->dev, "alloc cyclic decs error\n"); + return NULL; + } + desc->residue = buf_len; + + for (i = 0; i < num_periods; i++) { + if (direction == DMA_MEM_TO_DEV) + desc->sg[i].src_addr = buf_addr; + else if (direction == DMA_DEV_TO_MEM) + desc->sg[i].dst_addr = buf_addr; + else { + dev_err(c->device->dev, "direction type %d error\n", + direction); + goto free_desc; + } + desc->sg[i].len = period_len; + buf_addr += period_len; + } + + desc->num_sgs = num_periods; + desc->direction = direction; + desc->cyclic = true; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); + +free_desc: + kfree(desc); + return NULL; +} + +static enum dma_status gdma_dma_tx_status(struct dma_chan *c, + dma_cookie_t cookie, + struct dma_tx_state *state) +{ + struct gdma_dmaengine_chan *chan = to_gdma_dma_chan(c); + struct virt_dma_desc *vdesc; + enum dma_status status; + unsigned long flags; + struct gdma_dma_desc *desc; + + status = dma_cookie_status(c, cookie, state); + if (status == DMA_COMPLETE || !state) + return status; + + spin_lock_irqsave(&chan->vchan.lock, flags); + desc = chan->desc; + if (desc && (cookie == desc->vdesc.tx.cookie)) { + /* + * We never update edesc->residue in the cyclic case, so we + * can tell the remaining room to the end of the circular + * buffer. + */ + if (desc->cyclic) + state->residue = desc->residue - + ((chan->next_sg - 1) * desc->sg[0].len); + else + state->residue = desc->residue; + } else { + vdesc = vchan_find_desc(&chan->vchan, cookie); + if (vdesc) + state->residue = to_gdma_dma_desc(vdesc)->residue; + } + spin_unlock_irqrestore(&chan->vchan.lock, flags); + + dev_dbg(c->device->dev, "tx residue %d bytes\n", state->residue); + + return status; +} + +static void gdma_dma_free_chan_resources(struct dma_chan *c) +{ + vchan_free_chan_resources(to_virt_chan(c)); +} + +static void gdma_dma_desc_free(struct virt_dma_desc *vdesc) +{ + kfree(container_of(vdesc, struct gdma_dma_desc, vdesc)); +} + +static void gdma_dma_tasklet(unsigned long arg) +{ + struct gdma_dma_dev *dma_dev = (struct gdma_dma_dev *)arg; + struct gdma_dmaengine_chan *chan; + static unsigned int last_chan; + unsigned int i, chan_mask; + + /* record last chan to round robin all chans */ + i = last_chan; + chan_mask = dma_dev->data->chancnt - 1; + do { + /* + * on mt7621. when verify with dmatest with all + * channel is enable. we need to limit only two + * channel is working at the same time. otherwise the + * data will have problem. + */ + if (atomic_read(&dma_dev->cnt) >= 2) { + last_chan = i; + break; + } + + if (test_and_clear_bit(i, &dma_dev->chan_issued)) { + chan = &dma_dev->chan[i]; + if (chan->desc) { + atomic_inc(&dma_dev->cnt); + gdma_start_transfer(dma_dev, chan); + } else + dev_dbg(dma_dev->ddev.dev, "chan %d no desc to issue\n", chan->id); + + if (!dma_dev->chan_issued) + break; + } + + i = (i + 1) & chan_mask; + } while (i != last_chan); +} + +static void rt305x_gdma_init(struct gdma_dma_dev *dma_dev) +{ + uint32_t gct; + + /* all chans round robin */ + gdma_dma_write(dma_dev, GDMA_RT305X_GCT, GDMA_REG_GCT_ARBIT_RR); + + gct = gdma_dma_read(dma_dev, GDMA_RT305X_GCT); + dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", + (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, + 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & + GDMA_REG_GCT_CHAN_MASK)); +} + +static void rt3883_gdma_init(struct gdma_dma_dev *dma_dev) +{ + uint32_t gct; + + /* all chans round robin */ + gdma_dma_write(dma_dev, GDMA_REG_GCT, GDMA_REG_GCT_ARBIT_RR); + + gct = gdma_dma_read(dma_dev, GDMA_REG_GCT); + dev_info(dma_dev->ddev.dev, "revision: %d, channels: %d\n", + (gct >> GDMA_REG_GCT_VER_SHIFT) & GDMA_REG_GCT_VER_MASK, + 8 << ((gct >> GDMA_REG_GCT_CHAN_SHIFT) & + GDMA_REG_GCT_CHAN_MASK)); +} + +static struct gdma_data rt305x_gdma_data = { + .chancnt = 8, + .done_int_reg = GDMA_RT305X_STATUS_INT, + .init = rt305x_gdma_init, + .start_transfer = rt305x_gdma_start_transfer, +}; + +static struct gdma_data rt3883_gdma_data = { + .chancnt = 16, + .done_int_reg = GDMA_REG_DONE_INT, + .init = rt3883_gdma_init, + .start_transfer = rt3883_gdma_start_transfer, +}; + +static const struct of_device_id gdma_of_match_table[] = { + { .compatible = "ralink,rt305x-gdma", .data = &rt305x_gdma_data }, + { .compatible = "ralink,rt3883-gdma", .data = &rt3883_gdma_data }, + { }, +}; + +static int gdma_dma_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct gdma_dmaengine_chan *chan; + struct gdma_dma_dev *dma_dev; + struct dma_device *dd; + unsigned int i; + struct resource *res; + int ret; + int irq; + void __iomem *base; + struct gdma_data *data; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + match = of_match_device(gdma_of_match_table, &pdev->dev); + if (!match) + return -EINVAL; + data = (struct gdma_data *) match->data; + + dma_dev = devm_kzalloc(&pdev->dev, sizeof(*dma_dev) + + (sizeof(struct gdma_dmaengine_chan) * data->chancnt), + GFP_KERNEL); + if (!dma_dev) { + dev_err(&pdev->dev, "alloc dma device failed\n"); + return -EINVAL; + } + dma_dev->data = data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + dma_dev->base = base; + tasklet_init(&dma_dev->task, gdma_dma_tasklet, (unsigned long)dma_dev); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq\n"); + return -EINVAL; + } + ret = devm_request_irq(&pdev->dev, irq, gdma_dma_irq, + 0, dev_name(&pdev->dev), dma_dev); + if (ret) { + dev_err(&pdev->dev, "failed to request irq\n"); + return ret; + } + + device_reset(&pdev->dev); + + dd = &dma_dev->ddev; + dma_cap_set(DMA_MEMCPY, dd->cap_mask); + dma_cap_set(DMA_SLAVE, dd->cap_mask); + dma_cap_set(DMA_CYCLIC, dd->cap_mask); + dd->device_free_chan_resources = gdma_dma_free_chan_resources; + dd->device_prep_dma_memcpy = gdma_dma_prep_dma_memcpy; + dd->device_prep_slave_sg = gdma_dma_prep_slave_sg; + dd->device_prep_dma_cyclic = gdma_dma_prep_dma_cyclic; + dd->device_config = gdma_dma_config; + dd->device_terminate_all = gdma_dma_terminate_all; + dd->device_tx_status = gdma_dma_tx_status; + dd->device_issue_pending = gdma_dma_issue_pending; + + dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + dd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + + dd->dev = &pdev->dev; + dd->dev->dma_parms = &dma_dev->dma_parms; + dma_set_max_seg_size(dd->dev, GDMA_REG_CTRL0_TX_MASK); + INIT_LIST_HEAD(&dd->channels); + + for (i = 0; i < data->chancnt; i++) { + chan = &dma_dev->chan[i]; + chan->id = i; + chan->vchan.desc_free = gdma_dma_desc_free; + vchan_init(&chan->vchan, dd); + } + + /* init hardware */ + data->init(dma_dev); + + ret = dma_async_device_register(dd); + if (ret) { + dev_err(&pdev->dev, "failed to register dma device\n"); + return ret; + } + + ret = of_dma_controller_register(pdev->dev.of_node, + of_dma_xlate_by_chan_id, dma_dev); + if (ret) { + dev_err(&pdev->dev, "failed to register of dma controller\n"); + goto err_unregister; + } + + platform_set_drvdata(pdev, dma_dev); + + return 0; + +err_unregister: + dma_async_device_unregister(dd); + return ret; +} + +static int gdma_dma_remove(struct platform_device *pdev) +{ + struct gdma_dma_dev *dma_dev = platform_get_drvdata(pdev); + + tasklet_kill(&dma_dev->task); + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&dma_dev->ddev); + + return 0; +} + +static struct platform_driver gdma_dma_driver = { + .probe = gdma_dma_probe, + .remove = gdma_dma_remove, + .driver = { + .name = "gdma-rt2880", + .of_match_table = gdma_of_match_table, + }, +}; +module_platform_driver(gdma_dma_driver); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Ralink/MTK DMA driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/mt7621-dts/Kconfig b/drivers/staging/mt7621-dts/Kconfig new file mode 100644 index 000000000000..94a9e16c0b92 --- /dev/null +++ b/drivers/staging/mt7621-dts/Kconfig @@ -0,0 +1,5 @@ +config DTB_GNUBEE1 + bool "GnuBee1 NAS" + depends on SOC_MT7621 && DTB_RT_NONE + select BUILTIN_DTB + diff --git a/drivers/staging/mt7621-dts/Makefile b/drivers/staging/mt7621-dts/Makefile new file mode 100644 index 000000000000..195eba4a5c65 --- /dev/null +++ b/drivers/staging/mt7621-dts/Makefile @@ -0,0 +1,3 @@ +dtb-$(CONFIG_DTB_GNUBEE1) += gbpc1.dtb + +obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y)) diff --git a/drivers/staging/mt7621-dts/TODO b/drivers/staging/mt7621-dts/TODO new file mode 100644 index 000000000000..15803132c1ea --- /dev/null +++ b/drivers/staging/mt7621-dts/TODO @@ -0,0 +1,5 @@ + +- ensure all usage matches code +- ensure all features used are documented + +Cc: NeilBrown <neil@brown.name>
\ No newline at end of file diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts new file mode 100644 index 000000000000..515c7cbdd15e --- /dev/null +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -0,0 +1,143 @@ +/dts-v1/; + +#include "mt7621.dtsi" + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +/ { + compatible = "gnubee,gb-pc1", "mediatek,mt7621-soc"; + model = "GB-PC1"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x1c000000>, <0x20000000 0x4000000>; + }; + + chosen { + bootargs = "console=ttyS0,57600"; + }; + + palmbus: palmbus@1E000000 { + i2c@900 { + status = "okay"; + }; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <20>; + + reset { + label = "reset"; + gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; + linux,code = <KEY_RESTART>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + system { + label = "gb-pc1:green:system"; + gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + }; + + status { + label = "gb-pc1:green:status"; + gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; + }; + + lan1 { + label = "gb-pc1:green:lan1"; + gpios = <&gpio0 24 GPIO_ACTIVE_LOW>; + }; + + lan2 { + label = "gb-pc1:green:lan2"; + gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&sdhci { + status = "okay"; +}; + +&spi0 { + status = "okay"; + + m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <10000000>; + m25p,chunked-io = <32>; + + partition@0 { + label = "u-boot"; + reg = <0x0 0x30000>; + read-only; + }; + + partition@30000 { + label = "u-boot-env"; + reg = <0x30000 0x10000>; + read-only; + }; + + factory: partition@40000 { + label = "factory"; + reg = <0x40000 0x10000>; + read-only; + }; + + partition@50000 { + label = "firmware"; + reg = <0x50000 0xFB0000>; + }; + + }; +}; + +&sysclock { + compatible = "fixed-clock"; + clock-frequency = <90000000>; +}; + +&cpuclock { + compatible = "fixed-clock"; + clock-frequency = <900000000>; +}; + +&pcie { + status = "okay"; +}; + +ðernet { + //mtd-mac-address = <&factory 0xe000>; + gmac1: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-handle = <&phy1>; + }; + + mdio-bus { + phy1: ethernet-phy@1 { + reg = <1>; + phy-mode = "rgmii"; + }; + }; +}; + +&pinctrl { + state_default: pinctrl0 { + gpio { + ralink,group = "wdt", "rgmii2", "uart3"; + ralink,function = "gpio"; + }; + }; +}; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi new file mode 100644 index 000000000000..ebcaa8b1fc81 --- /dev/null +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -0,0 +1,471 @@ +#include <dt-bindings/interrupt-controller/mips-gic.h> + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mediatek,mt7621-soc"; + + cpus { + cpu@0 { + compatible = "mips,mips1004Kc"; + }; + + cpu@1 { + compatible = "mips,mips1004Kc"; + }; + }; + + cpuintc: cpuintc@0 { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + aliases { + serial0 = &uartlite; + }; + + cpuclock: cpuclock@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + + /* FIXME: there should be way to detect this */ + clock-frequency = <880000000>; + }; + + sysclock: sysclock@0 { + #clock-cells = <0>; + compatible = "fixed-clock"; + + /* FIXME: there should be way to detect this */ + clock-frequency = <50000000>; + }; + + palmbus: palmbus@1E000000 { + compatible = "palmbus"; + reg = <0x1E000000 0x100000>; + ranges = <0x0 0x1E000000 0x0FFFFF>; + + #address-cells = <1>; + #size-cells = <1>; + + sysc: sysc@0 { + compatible = "mtk,mt7621-sysc"; + reg = <0x0 0x100>; + }; + + wdt: wdt@100 { + compatible = "mtk,mt7621-wdt"; + reg = <0x100 0x100>; + }; + + gpio@600 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "mtk,mt7621-gpio"; + reg = <0x600 0x100>; + + gpio0: bank@0 { + reg = <0>; + compatible = "mtk,mt7621-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio1: bank@1 { + reg = <1>; + compatible = "mtk,mt7621-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio2: bank@2 { + reg = <2>; + compatible = "mtk,mt7621-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + i2c: i2c@900 { + compatible = "mediatek,mt7621-i2c"; + reg = <0x900 0x100>; + + clocks = <&sysclock>; + + resets = <&rstctrl 16>; + reset-names = "i2c"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + }; + + i2s: i2s@a00 { + compatible = "mediatek,mt7621-i2s"; + reg = <0xa00 0x100>; + + clocks = <&sysclock>; + + resets = <&rstctrl 17>; + reset-names = "i2s"; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 16 IRQ_TYPE_LEVEL_HIGH>; + + txdma-req = <2>; + rxdma-req = <3>; + + dmas = <&gdma 4>, + <&gdma 6>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + + memc: memc@5000 { + compatible = "mtk,mt7621-memc"; + reg = <0x300 0x100>; + }; + + cpc: cpc@1fbf0000 { + compatible = "mtk,mt7621-cpc"; + reg = <0x1fbf0000 0x8000>; + }; + + mc: mc@1fbf8000 { + compatible = "mtk,mt7621-mc"; + reg = <0x1fbf8000 0x8000>; + }; + + uartlite: uartlite@c00 { + compatible = "ns16550a"; + reg = <0xc00 0x100>; + + clocks = <&sysclock>; + clock-frequency = <50000000>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 26 IRQ_TYPE_LEVEL_HIGH>; + + reg-shift = <2>; + reg-io-width = <4>; + no-loopback-test; + }; + + spi0: spi@b00 { + status = "disabled"; + + compatible = "ralink,mt7621-spi"; + reg = <0xb00 0x100>; + + clocks = <&sysclock>; + + resets = <&rstctrl 18>; + reset-names = "spi"; + + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; + }; + + gdma: gdma@2800 { + compatible = "ralink,rt3883-gdma"; + reg = <0x2800 0x800>; + + resets = <&rstctrl 14>; + reset-names = "dma"; + + interrupt-parent = <&gic>; + interrupts = <0 13 4>; + + #dma-cells = <1>; + #dma-channels = <16>; + #dma-requests = <16>; + + status = "disabled"; + }; + + hsdma: hsdma@7000 { + compatible = "mediatek,mt7621-hsdma"; + reg = <0x7000 0x1000>; + + resets = <&rstctrl 5>; + reset-names = "hsdma"; + + interrupt-parent = <&gic>; + interrupts = <0 11 4>; + + #dma-cells = <1>; + #dma-channels = <1>; + #dma-requests = <1>; + + status = "disabled"; + }; + }; + + pinctrl: pinctrl { + compatible = "ralink,rt2880-pinmux"; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinctrl0 { + }; + + i2c_pins: i2c { + i2c { + ralink,group = "i2c"; + ralink,function = "i2c"; + }; + }; + + spi_pins: spi { + spi { + ralink,group = "spi"; + ralink,function = "spi"; + }; + }; + + uart1_pins: uart1 { + uart1 { + ralink,group = "uart1"; + ralink,function = "uart1"; + }; + }; + + uart2_pins: uart2 { + uart2 { + ralink,group = "uart2"; + ralink,function = "uart2"; + }; + }; + + uart3_pins: uart3 { + uart3 { + ralink,group = "uart3"; + ralink,function = "uart3"; + }; + }; + + rgmii1_pins: rgmii1 { + rgmii1 { + ralink,group = "rgmii1"; + ralink,function = "rgmii1"; + }; + }; + + rgmii2_pins: rgmii2 { + rgmii2 { + ralink,group = "rgmii2"; + ralink,function = "rgmii2"; + }; + }; + + mdio_pins: mdio { + mdio { + ralink,group = "mdio"; + ralink,function = "mdio"; + }; + }; + + pcie_pins: pcie { + pcie { + ralink,group = "pcie"; + ralink,function = "pcie rst"; + }; + }; + + nand_pins: nand { + spi-nand { + ralink,group = "spi"; + ralink,function = "nand1"; + }; + + sdhci-nand { + ralink,group = "sdhci"; + ralink,function = "nand2"; + }; + }; + + sdhci_pins: sdhci { + sdhci { + ralink,group = "sdhci"; + ralink,function = "sdhci"; + }; + }; + }; + + rstctrl: rstctrl { + compatible = "ralink,rt2880-reset"; + #reset-cells = <1>; + }; + + clkctrl: clkctrl { + compatible = "ralink,rt2880-clock"; + #clock-cells = <1>; + }; + + sdhci: sdhci@1E130000 { + status = "disabled"; + + compatible = "ralink,mt7620-sdhci"; + reg = <0x1E130000 0x4000>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>; + }; + + xhci: xhci@1E1C0000 { + status = "okay"; + + compatible = "mediatek,mt8173-xhci"; + reg = <0x1e1c0000 0x1000 + 0x1e1d0700 0x0100>; + reg-names = "mac", "ippc"; + + clocks = <&sysclock>; + clock-names = "sys_ck"; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 22 IRQ_TYPE_LEVEL_HIGH>; + }; + + gic: interrupt-controller@1fbc0000 { + compatible = "mti,gic"; + reg = <0x1fbc0000 0x2000>; + + interrupt-controller; + #interrupt-cells = <3>; + + mti,reserved-cpu-vectors = <7>; + + timer { + compatible = "mti,gic-timer"; + interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>; + clocks = <&cpuclock>; + }; + }; + + nand: nand@1e003000 { + status = "disabled"; + + compatible = "mtk,mt7621-nand"; + bank-width = <2>; + reg = <0x1e003000 0x800 + 0x1e003800 0x800>; + #address-cells = <1>; + #size-cells = <1>; + }; + + ethsys: syscon@1e000000 { + compatible = "mediatek,mt7621-ethsys", + "syscon"; + reg = <0x1e000000 0x1000>; + #clock-cells = <1>; + }; + + ethernet: ethernet@1e100000 { + compatible = "mediatek,mt7621-eth"; + reg = <0x1e100000 0x10000>; + + clocks = <&sysclock>; + clock-names = "ethif"; + + #address-cells = <1>; + #size-cells = <0>; + + resets = <&rstctrl 6 &rstctrl 23>; + reset-names = "fe", "eth"; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>; + + mediatek,ethsys = <ðsys>; + + mediatek,switch = <&gsw>; + + mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + phy1f: ethernet-phy@1f { + reg = <0x1f>; + phy-mode = "rgmii"; + }; + }; + }; + + gsw: gsw@1e110000 { + compatible = "mediatek,mt7621-gsw"; + reg = <0x1e110000 0x8000>; + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 23 IRQ_TYPE_LEVEL_HIGH>; + }; + + pcie: pcie@1e140000 { + compatible = "mediatek,mt7621-pci"; + reg = <0x1e140000 0x100 + 0x1e142000 0x100>; + + #address-cells = <3>; + #size-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins>; + + device_type = "pci"; + + bus-range = <0 255>; + ranges = < + 0x02000000 0 0x00000000 0x60000000 0 0x10000000 /* pci memory */ + 0x01000000 0 0x00000000 0x1e160000 0 0x00010000 /* io space */ + >; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 4 IRQ_TYPE_LEVEL_HIGH + GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH + GIC_SHARED 25 IRQ_TYPE_LEVEL_HIGH>; + + status = "disabled"; + + resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>; + reset-names = "pcie0", "pcie1", "pcie2"; + clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>; + clock-names = "pcie0", "pcie1", "pcie2"; + + pcie0 { + reg = <0x0000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + }; + + pcie1 { + reg = <0x0800 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + }; + + pcie2 { + reg = <0x1000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + }; + }; +}; diff --git a/drivers/staging/mt7621-eth/Documentation/devicetree/bindings/net/mediatek-net-gsw.txt b/drivers/staging/mt7621-eth/Documentation/devicetree/bindings/net/mediatek-net-gsw.txt new file mode 100644 index 000000000000..596b38552697 --- /dev/null +++ b/drivers/staging/mt7621-eth/Documentation/devicetree/bindings/net/mediatek-net-gsw.txt @@ -0,0 +1,48 @@ +Mediatek Gigabit Switch +======================= + +The mediatek gigabit switch can be found on Mediatek SoCs. + +Required properties: +- compatible: Should be "mediatek,mt7620-gsw", "mediatek,mt7621-gsw", + "mediatek,mt7623-gsw" +- reg: Address and length of the register set for the device +- interrupts: Should contain the gigabit switches interrupt + + +Additional required properties for ARM based SoCs: +- mediatek,reset-pin: phandle describing the reset GPIO +- clocks: the clocks used by the switch +- clock-names: the names of the clocks listed in the clocks property + these should be "trgpll", "esw", "gp2", "gp1" +- mt7530-supply: the phandle of the regulator used to power the switch +- mediatek,pctl-regmap: phandle to the port control regmap. this is used to + setup the drive current + + +Optional properties: +- interrupt-parent: Should be the phandle for the interrupt controller + that services interrupts for this device + +Example: + +gsw: switch@1b100000 { + compatible = "mediatek,mt7623-gsw"; + reg = <0 0x1b110000 0 0x300000>; + + interrupt-parent = <&pio>; + interrupts = <168 IRQ_TYPE_EDGE_RISING>; + + clocks = <&apmixedsys CLK_APMIXED_TRGPLL>, + <ðsys CLK_ETHSYS_ESW>, + <ðsys CLK_ETHSYS_GP2>, + <ðsys CLK_ETHSYS_GP1>; + clock-names = "trgpll", "esw", "gp2", "gp1"; + + mt7530-supply = <&mt6323_vpa_reg>; + + mediatek,pctl-regmap = <&syscfg_pctl_a>; + mediatek,reset-pin = <&pio 15 0>; + + status = "okay"; +}; diff --git a/drivers/staging/mt7621-eth/Kconfig b/drivers/staging/mt7621-eth/Kconfig new file mode 100644 index 000000000000..44ea86c7a96c --- /dev/null +++ b/drivers/staging/mt7621-eth/Kconfig @@ -0,0 +1,39 @@ +config NET_VENDOR_MEDIATEK_STAGING + bool "MediaTek ethernet driver - staging version" + depends on RALINK + ---help--- + If you have an MT7621 Mediatek SoC with ethernet, say Y. + +if NET_VENDOR_MEDIATEK_STAGING +choice + prompt "MAC type" + +config NET_MEDIATEK_MT7621 + bool "MT7621" + depends on MIPS && SOC_MT7621 + +endchoice + +config NET_MEDIATEK_SOC_STAGING + tristate "MediaTek SoC Gigabit Ethernet support" + depends on NET_VENDOR_MEDIATEK_STAGING + select PHYLIB + ---help--- + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. + +config NET_MEDIATEK_MDIO + def_bool NET_MEDIATEK_SOC_STAGING + depends on NET_MEDIATEK_MT7621 + select PHYLIB + +config NET_MEDIATEK_MDIO_MT7620 + def_bool NET_MEDIATEK_SOC_STAGING + depends on NET_MEDIATEK_MT7621 + select NET_MEDIATEK_MDIO + +config NET_MEDIATEK_GSW_MT7621 + def_tristate NET_MEDIATEK_SOC_STAGING + depends on NET_MEDIATEK_MT7621 + +endif #NET_VENDOR_MEDIATEK_STAGING diff --git a/drivers/staging/mt7621-eth/Makefile b/drivers/staging/mt7621-eth/Makefile new file mode 100644 index 000000000000..018bcc3596b3 --- /dev/null +++ b/drivers/staging/mt7621-eth/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Ralink SoCs built-in ethernet macs +# + +mtk-eth-soc-y += mtk_eth_soc.o ethtool.o + +mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MDIO) += mdio.o +mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MDIO_MT7620) += mdio_mt7620.o + +mtk-eth-soc-$(CONFIG_NET_MEDIATEK_MT7621) += soc_mt7621.o + +obj-$(CONFIG_NET_MEDIATEK_GSW_MT7621) += gsw_mt7621.o + +obj-$(CONFIG_NET_MEDIATEK_SOC_STAGING) += mtk-eth-soc.o diff --git a/drivers/staging/mt7621-eth/TODO b/drivers/staging/mt7621-eth/TODO new file mode 100644 index 000000000000..f9e47d4b4cd4 --- /dev/null +++ b/drivers/staging/mt7621-eth/TODO @@ -0,0 +1,13 @@ + +- verify devicetree documentation is consistent with code +- fix ethtool - currently doesn't return valid data. +- general code review and clean up +- add support for second MAC on mt7621 +- convert gsw code to use switchdev interfaces +- md7620_mmi_write etc should probably be wrapped + in a regmap abstraction. +- Get soc_mt7621 to work with QDMA TX if possible. +- Ensure phys are correctly configured when a cable + is plugged in. + +Cc: NeilBrown <neil@brown.name> diff --git a/drivers/staging/mt7621-eth/ethtool.c b/drivers/staging/mt7621-eth/ethtool.c new file mode 100644 index 000000000000..38ba0c040aba --- /dev/null +++ b/drivers/staging/mt7621-eth/ethtool.c @@ -0,0 +1,225 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#include "mtk_eth_soc.h" + +static const char mtk_gdma_str[][ETH_GSTRING_LEN] = { +#define _FE(x...) # x, +MTK_STAT_REG_DECLARE +#undef _FE +}; + +static int mtk_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + struct mtk_mac *mac = netdev_priv(dev); + int err; + + if (!mac->phy_dev) + return -ENODEV; + + if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) { + err = phy_read_status(mac->phy_dev); + if (err) + return -ENODEV; + } + + phy_ethtool_ksettings_get(mac->phy_dev, cmd); + return 0; +} + +static int mtk_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) +{ + struct mtk_mac *mac = netdev_priv(dev); + + if (!mac->phy_dev) + return -ENODEV; + + if (cmd->base.phy_address != mac->phy_dev->mdio.addr) { + if (mac->hw->phy->phy_node[cmd->base.phy_address]) { + mac->phy_dev = mac->hw->phy->phy[cmd->base.phy_address]; + mac->phy_flags = MTK_PHY_FLAG_PORT; + } else if (mac->hw->mii_bus) { + mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus, cmd->base.phy_address); + if (!mac->phy_dev) + return -ENODEV; + mac->phy_flags = MTK_PHY_FLAG_ATTACH; + } else { + return -ENODEV; + } + } + + return phy_ethtool_ksettings_set(mac->phy_dev, cmd); + +} + +static void mtk_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_soc_data *soc = mac->hw->soc; + + strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver)); + strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info)); + + if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) + info->n_stats = ARRAY_SIZE(mtk_gdma_str); +} + +static u32 mtk_get_msglevel(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + + return mac->hw->msg_enable; +} + +static void mtk_set_msglevel(struct net_device *dev, u32 value) +{ + struct mtk_mac *mac = netdev_priv(dev); + + mac->hw->msg_enable = value; +} + +static int mtk_nway_reset(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + + if (!mac->phy_dev) + return -EOPNOTSUPP; + + return genphy_restart_aneg(mac->phy_dev); +} + +static u32 mtk_get_link(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + int err; + + if (!mac->phy_dev) + goto out_get_link; + + if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) { + err = genphy_update_link(mac->phy_dev); + if (err) + goto out_get_link; + } + + return mac->phy_dev->link; + +out_get_link: + return ethtool_op_get_link(dev); +} + +static int mtk_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct mtk_mac *mac = netdev_priv(dev); + + if ((ring->tx_pending < 2) || + (ring->rx_pending < 2) || + (ring->rx_pending > mac->hw->soc->dma_ring_size) || + (ring->tx_pending > mac->hw->soc->dma_ring_size)) + return -EINVAL; + + dev->netdev_ops->ndo_stop(dev); + + mac->hw->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1); + mac->hw->rx_ring[0].rx_ring_size = BIT(fls(ring->rx_pending) - 1); + + return dev->netdev_ops->ndo_open(dev); +} + +static void mtk_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct mtk_mac *mac = netdev_priv(dev); + + ring->rx_max_pending = mac->hw->soc->dma_ring_size; + ring->tx_max_pending = mac->hw->soc->dma_ring_size; + ring->rx_pending = mac->hw->rx_ring[0].rx_ring_size; + ring->tx_pending = mac->hw->tx_ring.tx_ring_size; +} + +static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(data, *mtk_gdma_str, sizeof(mtk_gdma_str)); + break; + } +} + +static int mtk_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(mtk_gdma_str); + default: + return -EOPNOTSUPP; + } +} + +static void mtk_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_hw_stats *hwstats = mac->hw_stats; + u64 *data_src, *data_dst; + unsigned int start; + int i; + + if (netif_running(dev) && netif_device_present(dev)) { + if (spin_trylock(&hwstats->stats_lock)) { + mtk_stats_update_mac(mac); + spin_unlock(&hwstats->stats_lock); + } + } + + do { + data_src = &hwstats->tx_bytes; + data_dst = data; + start = u64_stats_fetch_begin_irq(&hwstats->syncp); + + for (i = 0; i < ARRAY_SIZE(mtk_gdma_str); i++) + *data_dst++ = *data_src++; + + } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); +} + +static struct ethtool_ops mtk_ethtool_ops = { + .get_link_ksettings = mtk_get_link_ksettings, + .set_link_ksettings = mtk_set_link_ksettings, + .get_drvinfo = mtk_get_drvinfo, + .get_msglevel = mtk_get_msglevel, + .set_msglevel = mtk_set_msglevel, + .nway_reset = mtk_nway_reset, + .get_link = mtk_get_link, + .set_ringparam = mtk_set_ringparam, + .get_ringparam = mtk_get_ringparam, +}; + +void mtk_set_ethtool_ops(struct net_device *netdev) +{ + struct mtk_mac *mac = netdev_priv(netdev); + struct mtk_soc_data *soc = mac->hw->soc; + + if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) { + mtk_ethtool_ops.get_strings = mtk_get_strings; + mtk_ethtool_ops.get_sset_count = mtk_get_sset_count; + mtk_ethtool_ops.get_ethtool_stats = mtk_get_ethtool_stats; + } + + netdev->ethtool_ops = &mtk_ethtool_ops; +} diff --git a/drivers/staging/mt7621-eth/ethtool.h b/drivers/staging/mt7621-eth/ethtool.h new file mode 100644 index 000000000000..40b4cf011660 --- /dev/null +++ b/drivers/staging/mt7621-eth/ethtool.h @@ -0,0 +1,22 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#ifndef MTK_ETHTOOL_H +#define MTK_ETHTOOL_H + +#include <linux/ethtool.h> + +void mtk_set_ethtool_ops(struct net_device *netdev); + +#endif /* MTK_ETHTOOL_H */ diff --git a/drivers/staging/mt7621-eth/gsw_mt7620.h b/drivers/staging/mt7621-eth/gsw_mt7620.h new file mode 100644 index 000000000000..1766939e2101 --- /dev/null +++ b/drivers/staging/mt7621-eth/gsw_mt7620.h @@ -0,0 +1,277 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#ifndef _RALINK_GSW_MT7620_H__ +#define _RALINK_GSW_MT7620_H__ + +#define GSW_REG_PHY_TIMEOUT (5 * HZ) + +#define MT7620_GSW_REG_PIAC 0x0004 + +#define GSW_NUM_VLANS 16 +#define GSW_NUM_VIDS 4096 +#define GSW_NUM_PORTS 7 +#define GSW_PORT6 6 + +#define GSW_MDIO_ACCESS BIT(31) +#define GSW_MDIO_READ BIT(19) +#define GSW_MDIO_WRITE BIT(18) +#define GSW_MDIO_START BIT(16) +#define GSW_MDIO_ADDR_SHIFT 20 +#define GSW_MDIO_REG_SHIFT 25 + +#define GSW_REG_PORT_PMCR(x) (0x3000 + (x * 0x100)) +#define GSW_REG_PORT_STATUS(x) (0x3008 + (x * 0x100)) +#define GSW_REG_SMACCR0 0x3fE4 +#define GSW_REG_SMACCR1 0x3fE8 +#define GSW_REG_CKGCR 0x3ff0 + +#define GSW_REG_IMR 0x7008 +#define GSW_REG_ISR 0x700c +#define GSW_REG_GPC1 0x7014 + +#define SYSC_REG_CHIP_REV_ID 0x0c +#define SYSC_REG_CFG 0x10 +#define SYSC_REG_CFG1 0x14 +#define RST_CTRL_MCM BIT(2) +#define SYSC_PAD_RGMII2_MDIO 0x58 +#define SYSC_GPIO_MODE 0x60 + +#define PORT_IRQ_ST_CHG 0x7f + +#define MT7621_ESW_PHY_POLLING 0x0000 +#define MT7620_ESW_PHY_POLLING 0x7000 + +#define PMCR_IPG BIT(18) +#define PMCR_MAC_MODE BIT(16) +#define PMCR_FORCE BIT(15) +#define PMCR_TX_EN BIT(14) +#define PMCR_RX_EN BIT(13) +#define PMCR_BACKOFF BIT(9) +#define PMCR_BACKPRES BIT(8) +#define PMCR_RX_FC BIT(5) +#define PMCR_TX_FC BIT(4) +#define PMCR_SPEED(_x) (_x << 2) +#define PMCR_DUPLEX BIT(1) +#define PMCR_LINK BIT(0) + +#define PHY_AN_EN BIT(31) +#define PHY_PRE_EN BIT(30) +#define PMY_MDC_CONF(_x) ((_x & 0x3f) << 24) + +/* ethernet subsystem config register */ +#define ETHSYS_SYSCFG0 0x14 +/* ethernet subsystem clock register */ +#define ETHSYS_CLKCFG0 0x2c +#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) + +/* p5 RGMII wrapper TX clock control register */ +#define MT7530_P5RGMIITXCR 0x7b04 +/* p5 RGMII wrapper RX clock control register */ +#define MT7530_P5RGMIIRXCR 0x7b00 +/* TRGMII TDX ODT registers */ +#define MT7530_TRGMII_TD0_ODT 0x7a54 +#define MT7530_TRGMII_TD1_ODT 0x7a5c +#define MT7530_TRGMII_TD2_ODT 0x7a64 +#define MT7530_TRGMII_TD3_ODT 0x7a6c +#define MT7530_TRGMII_TD4_ODT 0x7a74 +#define MT7530_TRGMII_TD5_ODT 0x7a7c +/* TRGMII TCK ctrl register */ +#define MT7530_TRGMII_TCK_CTRL 0x7a78 +/* TRGMII Tx ctrl register */ +#define MT7530_TRGMII_TXCTRL 0x7a40 +/* port 6 extended control register */ +#define MT7530_P6ECR 0x7830 +/* IO driver control register */ +#define MT7530_IO_DRV_CR 0x7810 +/* top signal control register */ +#define MT7530_TOP_SIG_CTRL 0x7808 +/* modified hwtrap register */ +#define MT7530_MHWTRAP 0x7804 +/* hwtrap status register */ +#define MT7530_HWTRAP 0x7800 +/* status interrupt register */ +#define MT7530_SYS_INT_STS 0x700c +/* system nterrupt register */ +#define MT7530_SYS_INT_EN 0x7008 +/* system control register */ +#define MT7530_SYS_CTRL 0x7000 +/* port MAC status register */ +#define MT7530_PMSR_P(x) (0x3008 + (x * 0x100)) +/* port MAC control register */ +#define MT7530_PMCR_P(x) (0x3000 + (x * 0x100)) + +#define MT7621_XTAL_SHIFT 6 +#define MT7621_XTAL_MASK 0x7 +#define MT7621_XTAL_25 6 +#define MT7621_XTAL_40 3 +#define MT7621_MDIO_DRV_MASK (3 << 4) +#define MT7621_GE1_MODE_MASK (3 << 12) + +#define TRGMII_TXCTRL_TXC_INV BIT(30) +#define P6ECR_INTF_MODE_RGMII BIT(1) +#define P5RGMIIRXCR_C_ALIGN BIT(8) +#define P5RGMIIRXCR_DELAY_2 BIT(1) +#define P5RGMIITXCR_DELAY_2 (BIT(8) | BIT(2)) + +/* TOP_SIG_CTRL bits */ +#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16)) + +/* MHWTRAP bits */ +#define MHWTRAP_MANUAL BIT(16) +#define MHWTRAP_P5_MAC_SEL BIT(13) +#define MHWTRAP_P6_DIS BIT(8) +#define MHWTRAP_P5_RGMII_MODE BIT(7) +#define MHWTRAP_P5_DIS BIT(6) +#define MHWTRAP_PHY_ACCESS BIT(5) + +/* HWTRAP bits */ +#define HWTRAP_XTAL_SHIFT 9 +#define HWTRAP_XTAL_MASK 0x3 + +/* SYS_CTRL bits */ +#define SYS_CTRL_SW_RST BIT(1) +#define SYS_CTRL_REG_RST BIT(0) + +/* PMCR bits */ +#define PMCR_IFG_XMIT_96 BIT(18) +#define PMCR_MAC_MODE BIT(16) +#define PMCR_FORCE_MODE BIT(15) +#define PMCR_TX_EN BIT(14) +#define PMCR_RX_EN BIT(13) +#define PMCR_BACK_PRES_EN BIT(9) +#define PMCR_BACKOFF_EN BIT(8) +#define PMCR_TX_FC_EN BIT(5) +#define PMCR_RX_FC_EN BIT(4) +#define PMCR_FORCE_SPEED_1000 BIT(3) +#define PMCR_FORCE_FDX BIT(1) +#define PMCR_FORCE_LNK BIT(0) +#define PMCR_FIXED_LINK (PMCR_IFG_XMIT_96 | PMCR_MAC_MODE | \ + PMCR_FORCE_MODE | PMCR_TX_EN | PMCR_RX_EN | \ + PMCR_BACK_PRES_EN | PMCR_BACKOFF_EN | \ + PMCR_FORCE_SPEED_1000 | PMCR_FORCE_FDX | \ + PMCR_FORCE_LNK) + +#define PMCR_FIXED_LINK_FC (PMCR_FIXED_LINK | \ + PMCR_TX_FC_EN | PMCR_RX_FC_EN) + +/* TRGMII control registers */ +#define GSW_INTF_MODE 0x390 +#define GSW_TRGMII_TD0_ODT 0x354 +#define GSW_TRGMII_TD1_ODT 0x35c +#define GSW_TRGMII_TD2_ODT 0x364 +#define GSW_TRGMII_TD3_ODT 0x36c +#define GSW_TRGMII_TXCTL_ODT 0x374 +#define GSW_TRGMII_TCK_ODT 0x37c +#define GSW_TRGMII_RCK_CTRL 0x300 + +#define INTF_MODE_TRGMII BIT(1) +#define TRGMII_RCK_CTRL_RX_RST BIT(31) + +/* Mac control registers */ +#define MTK_MAC_P2_MCR 0x200 +#define MTK_MAC_P1_MCR 0x100 + +#define MAC_MCR_MAX_RX_2K BIT(29) +#define MAC_MCR_IPG_CFG (BIT(18) | BIT(16)) +#define MAC_MCR_FORCE_MODE BIT(15) +#define MAC_MCR_TX_EN BIT(14) +#define MAC_MCR_RX_EN BIT(13) +#define MAC_MCR_BACKOFF_EN BIT(9) +#define MAC_MCR_BACKPR_EN BIT(8) +#define MAC_MCR_FORCE_RX_FC BIT(5) +#define MAC_MCR_FORCE_TX_FC BIT(4) +#define MAC_MCR_SPEED_1000 BIT(3) +#define MAC_MCR_FORCE_DPX BIT(1) +#define MAC_MCR_FORCE_LINK BIT(0) +#define MAC_MCR_FIXED_LINK (MAC_MCR_MAX_RX_2K | MAC_MCR_IPG_CFG | \ + MAC_MCR_FORCE_MODE | MAC_MCR_TX_EN | \ + MAC_MCR_RX_EN | MAC_MCR_BACKOFF_EN | \ + MAC_MCR_BACKPR_EN | MAC_MCR_FORCE_RX_FC | \ + MAC_MCR_FORCE_TX_FC | MAC_MCR_SPEED_1000 | \ + MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_LINK) +#define MAC_MCR_FIXED_LINK_FC (MAC_MCR_MAX_RX_2K | MAC_MCR_IPG_CFG | \ + MAC_MCR_FIXED_LINK) + +/* possible XTAL speed */ +#define MT7623_XTAL_40 0 +#define MT7623_XTAL_20 1 +#define MT7623_XTAL_25 3 + +/* GPIO port control registers */ +#define GPIO_OD33_CTRL8 0x4c0 +#define GPIO_BIAS_CTRL 0xed0 +#define GPIO_DRV_SEL10 0xf00 + +/* on MT7620 the functio of port 4 can be software configured */ +enum { + PORT4_EPHY = 0, + PORT4_EXT, +}; + +/* struct mt7620_gsw - the structure that holds the SoC specific data + * @dev: The Device struct + * @base: The base address + * @piac_offset: The PIAC base may change depending on SoC + * @irq: The IRQ we are using + * @port4: The port4 mode on MT7620 + * @autopoll: Is MDIO autopolling enabled + * @ethsys: The ethsys register map + * @pctl: The pin control register map + * @clk_gsw: The switch clock + * @clk_gp1: The gmac1 clock + * @clk_gp2: The gmac2 clock + * @clk_trgpll: The trgmii pll clock + */ +struct mt7620_gsw { + struct device *dev; + void __iomem *base; + u32 piac_offset; + int irq; + int port4; + unsigned long int autopoll; + + struct regmap *ethsys; + struct regmap *pctl; + + struct clk *clk_gsw; + struct clk *clk_gp1; + struct clk *clk_gp2; + struct clk *clk_trgpll; +}; + +/* switch register I/O wrappers */ +void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg); +u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg); + +/* the callback used by the driver core to bringup the switch */ +int mtk_gsw_init(struct mtk_eth *eth); + +/* MDIO access wrappers */ +int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val); +int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg); +void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port); +int mt7620_has_carrier(struct mtk_eth *eth); +void mt7620_print_link_state(struct mtk_eth *eth, int port, int link, + int speed, int duplex); +void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val); +u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg); +void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg); + +u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr, + u32 phy_register, u32 write_data); +u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg); +void mt7620_handle_carrier(struct mtk_eth *eth); + +#endif diff --git a/drivers/staging/mt7621-eth/gsw_mt7621.c b/drivers/staging/mt7621-eth/gsw_mt7621.c new file mode 100644 index 000000000000..ce8d7d7577c7 --- /dev/null +++ b/drivers/staging/mt7621-eth/gsw_mt7621.c @@ -0,0 +1,298 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#include <ralink_regs.h> + +#include "mtk_eth_soc.h" +#include "gsw_mt7620.h" + +void mtk_switch_w32(struct mt7620_gsw *gsw, u32 val, unsigned reg) +{ + iowrite32(val, gsw->base + reg); +} +EXPORT_SYMBOL_GPL(mtk_switch_w32); + +u32 mtk_switch_r32(struct mt7620_gsw *gsw, unsigned reg) +{ + return ioread32(gsw->base + reg); +} +EXPORT_SYMBOL_GPL(mtk_switch_r32); + +static irqreturn_t gsw_interrupt_mt7621(int irq, void *_eth) +{ + struct mtk_eth *eth = (struct mtk_eth *)_eth; + struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv; + u32 reg, i; + + reg = mt7530_mdio_r32(gsw, MT7530_SYS_INT_STS); + + for (i = 0; i < 5; i++) { + unsigned int link; + + if ((reg & BIT(i)) == 0) + continue; + + link = mt7530_mdio_r32(gsw, MT7530_PMSR_P(i)) & 0x1; + + if (link == eth->link[i]) + continue; + + eth->link[i] = link; + if (link) + netdev_info(*eth->netdev, + "port %d link up\n", i); + else + netdev_info(*eth->netdev, + "port %d link down\n", i); + } + + mt7530_mdio_w32(gsw, MT7530_SYS_INT_STS, 0x1f); + + return IRQ_HANDLED; +} + +static void mt7621_hw_init(struct mtk_eth *eth, struct mt7620_gsw *gsw, + struct device_node *np) +{ + u32 i; + u32 val; + + /* hardware reset the switch */ + mtk_reset(eth, RST_CTRL_MCM); + mdelay(10); + + /* reduce RGMII2 PAD driving strength */ + rt_sysc_m32(MT7621_MDIO_DRV_MASK, 0, SYSC_PAD_RGMII2_MDIO); + + /* gpio mux - RGMII1=Normal mode */ + rt_sysc_m32(BIT(14), 0, SYSC_GPIO_MODE); + + /* set GMAC1 RGMII mode */ + rt_sysc_m32(MT7621_GE1_MODE_MASK, 0, SYSC_REG_CFG1); + + /* enable MDIO to control MT7530 */ + rt_sysc_m32(3 << 12, 0, SYSC_GPIO_MODE); + + /* turn off all PHYs */ + for (i = 0; i <= 4; i++) { + val = _mt7620_mii_read(gsw, i, 0x0); + val |= BIT(11); + _mt7620_mii_write(gsw, i, 0x0, val); + } + + /* reset the switch */ + mt7530_mdio_w32(gsw, MT7530_SYS_CTRL, + SYS_CTRL_SW_RST | SYS_CTRL_REG_RST); + usleep_range(10, 20); + + if ((rt_sysc_r32(SYSC_REG_CHIP_REV_ID) & 0xFFFF) == 0x0101) { + /* GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536 */ + mtk_switch_w32(gsw, MAC_MCR_FIXED_LINK, MTK_MAC_P2_MCR); + mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK); + } else { + /* GE1, Force 1000M/FD, FC ON, MAX_RX_LENGTH 1536 */ + mtk_switch_w32(gsw, MAC_MCR_FIXED_LINK_FC, MTK_MAC_P1_MCR); + mt7530_mdio_w32(gsw, MT7530_PMCR_P(6), PMCR_FIXED_LINK_FC); + } + + /* GE2, Link down */ + mtk_switch_w32(gsw, MAC_MCR_FORCE_MODE, MTK_MAC_P2_MCR); + + /* Enable Port 6, P5 as GMAC5, P5 disable */ + val = mt7530_mdio_r32(gsw, MT7530_MHWTRAP); + /* Enable Port 6 */ + val &= ~MHWTRAP_P6_DIS; + /* Disable Port 5 */ + val |= MHWTRAP_P5_DIS; + /* manual override of HW-Trap */ + val |= MHWTRAP_MANUAL; + mt7530_mdio_w32(gsw, MT7530_MHWTRAP, val); + + val = rt_sysc_r32(SYSC_REG_CFG); + val = (val >> MT7621_XTAL_SHIFT) & MT7621_XTAL_MASK; + if (val < MT7621_XTAL_25 && val >= MT7621_XTAL_40) { + /* 40Mhz */ + + /* disable MT7530 core clock */ + _mt7620_mii_write(gsw, 0, 13, 0x1f); + _mt7620_mii_write(gsw, 0, 14, 0x410); + _mt7620_mii_write(gsw, 0, 13, 0x401f); + _mt7620_mii_write(gsw, 0, 14, 0x0); + + /* disable MT7530 PLL */ + _mt7620_mii_write(gsw, 0, 13, 0x1f); + _mt7620_mii_write(gsw, 0, 14, 0x40d); + _mt7620_mii_write(gsw, 0, 13, 0x401f); + _mt7620_mii_write(gsw, 0, 14, 0x2020); + + /* for MT7530 core clock = 500Mhz */ + _mt7620_mii_write(gsw, 0, 13, 0x1f); + _mt7620_mii_write(gsw, 0, 14, 0x40e); + _mt7620_mii_write(gsw, 0, 13, 0x401f); + _mt7620_mii_write(gsw, 0, 14, 0x119); + + /* enable MT7530 PLL */ + _mt7620_mii_write(gsw, 0, 13, 0x1f); + _mt7620_mii_write(gsw, 0, 14, 0x40d); + _mt7620_mii_write(gsw, 0, 13, 0x401f); + _mt7620_mii_write(gsw, 0, 14, 0x2820); + + usleep_range(20, 40); + + /* enable MT7530 core clock */ + _mt7620_mii_write(gsw, 0, 13, 0x1f); + _mt7620_mii_write(gsw, 0, 14, 0x410); + _mt7620_mii_write(gsw, 0, 13, 0x401f); + } + + /* RGMII */ + _mt7620_mii_write(gsw, 0, 14, 0x1); + + /* set MT7530 central align */ + mt7530_mdio_m32(gsw, BIT(0), P6ECR_INTF_MODE_RGMII, MT7530_P6ECR); + mt7530_mdio_m32(gsw, TRGMII_TXCTRL_TXC_INV, 0, + MT7530_TRGMII_TXCTRL); + mt7530_mdio_w32(gsw, MT7530_TRGMII_TCK_CTRL, 0x855); + + /* delay setting for 10/1000M */ + mt7530_mdio_w32(gsw, MT7530_P5RGMIIRXCR, + P5RGMIIRXCR_C_ALIGN | P5RGMIIRXCR_DELAY_2); + mt7530_mdio_w32(gsw, MT7530_P5RGMIITXCR, 0x14); + + /* lower Tx Driving*/ + mt7530_mdio_w32(gsw, MT7530_TRGMII_TD0_ODT, 0x44); + mt7530_mdio_w32(gsw, MT7530_TRGMII_TD1_ODT, 0x44); + mt7530_mdio_w32(gsw, MT7530_TRGMII_TD2_ODT, 0x44); + mt7530_mdio_w32(gsw, MT7530_TRGMII_TD3_ODT, 0x44); + mt7530_mdio_w32(gsw, MT7530_TRGMII_TD4_ODT, 0x44); + mt7530_mdio_w32(gsw, MT7530_TRGMII_TD5_ODT, 0x44); + + /* turn on all PHYs */ + for (i = 0; i <= 4; i++) { + val = _mt7620_mii_read(gsw, i, 0); + val &= ~BIT(11); + _mt7620_mii_write(gsw, i, 0, val); + } + +#define MT7530_NUM_PORTS 8 +#define REG_ESW_PORT_PCR(x) (0x2004 | ((x) << 8)) +#define REG_ESW_PORT_PVC(x) (0x2010 | ((x) << 8)) +#define REG_ESW_PORT_PPBV1(x) (0x2014 | ((x) << 8)) +#define MT7530_CPU_PORT 6 + + /* This is copied from mt7530_apply_config in libreCMC driver */ + { + int i; + for (i = 0; i < MT7530_NUM_PORTS; i++) + mt7530_mdio_w32(gsw, REG_ESW_PORT_PCR(i), 0x00400000); + + mt7530_mdio_w32(gsw, REG_ESW_PORT_PCR(MT7530_CPU_PORT), 0x00ff0000); + + for (i = 0; i < MT7530_NUM_PORTS; i++) + mt7530_mdio_w32(gsw, REG_ESW_PORT_PVC(i), 0x810000c0); + + } + + /* enable irq */ + mt7530_mdio_m32(gsw, 0, 3 << 16, MT7530_TOP_SIG_CTRL); + mt7530_mdio_w32(gsw, MT7530_SYS_INT_EN, 0x1f); + +} + +static const struct of_device_id mediatek_gsw_match[] = { + { .compatible = "mediatek,mt7621-gsw" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mediatek_gsw_match); + +int mtk_gsw_init(struct mtk_eth *eth) +{ + struct device_node *np = eth->switch_np; + struct platform_device *pdev = of_find_device_by_node(np); + struct mt7620_gsw *gsw; + + if (!pdev) + return -ENODEV; + + if (!of_device_is_compatible(np, mediatek_gsw_match->compatible)) + return -EINVAL; + + gsw = platform_get_drvdata(pdev); + eth->sw_priv = gsw; + + if (!gsw->irq) + return -EINVAL; + + request_irq(gsw->irq, gsw_interrupt_mt7621, 0, + "gsw", eth); + disable_irq(gsw->irq); + + mt7621_hw_init(eth, gsw, np); + + enable_irq(gsw->irq); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_gsw_init); + +static int mt7621_gsw_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct mt7620_gsw *gsw; + + gsw = devm_kzalloc(&pdev->dev, sizeof(struct mt7620_gsw), GFP_KERNEL); + if (!gsw) + return -ENOMEM; + + gsw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gsw->base)) + return PTR_ERR(gsw->base); + + gsw->dev = &pdev->dev; + gsw->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + + platform_set_drvdata(pdev, gsw); + + return 0; +} + +static int mt7621_gsw_remove(struct platform_device *pdev) +{ + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver gsw_driver = { + .probe = mt7621_gsw_probe, + .remove = mt7621_gsw_remove, + .driver = { + .name = "mt7621-gsw", + .owner = THIS_MODULE, + .of_match_table = mediatek_gsw_match, + }, +}; + +module_platform_driver(gsw_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +MODULE_DESCRIPTION("GBit switch driver for Mediatek MT7621 SoC"); diff --git a/drivers/staging/mt7621-eth/mdio.c b/drivers/staging/mt7621-eth/mdio.c new file mode 100644 index 000000000000..9d713078ef90 --- /dev/null +++ b/drivers/staging/mt7621-eth/mdio.c @@ -0,0 +1,271 @@ +/* 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; version 2 of the License + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/phy.h> +#include <linux/of_net.h> +#include <linux/of_mdio.h> + +#include "mtk_eth_soc.h" +#include "mdio.h" + +static int mtk_mdio_reset(struct mii_bus *bus) +{ + /* TODO */ + return 0; +} + +static void mtk_phy_link_adjust(struct net_device *dev) +{ + struct mtk_eth *eth = netdev_priv(dev); + unsigned long flags; + int i; + + spin_lock_irqsave(ð->phy->lock, flags); + for (i = 0; i < 8; i++) { + if (eth->phy->phy_node[i]) { + struct phy_device *phydev = eth->phy->phy[i]; + int status_change = 0; + + if (phydev->link) + if (eth->phy->duplex[i] != phydev->duplex || + eth->phy->speed[i] != phydev->speed) + status_change = 1; + + if (phydev->link != eth->link[i]) + status_change = 1; + + switch (phydev->speed) { + case SPEED_1000: + case SPEED_100: + case SPEED_10: + eth->link[i] = phydev->link; + eth->phy->duplex[i] = phydev->duplex; + eth->phy->speed[i] = phydev->speed; + + if (status_change && + eth->soc->mdio_adjust_link) + eth->soc->mdio_adjust_link(eth, i); + break; + } + } + } +} + +int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac, + struct device_node *phy_node) +{ + const __be32 *_port = NULL; + struct phy_device *phydev; + int phy_mode, port; + + _port = of_get_property(phy_node, "reg", NULL); + + if (!_port || (be32_to_cpu(*_port) >= 0x20)) { + pr_err("%s: invalid port id\n", phy_node->name); + return -EINVAL; + } + port = be32_to_cpu(*_port); + phy_mode = of_get_phy_mode(phy_node); + if (phy_mode < 0) { + dev_err(eth->dev, "incorrect phy-mode %d\n", phy_mode); + eth->phy->phy_node[port] = NULL; + return -EINVAL; + } + + phydev = of_phy_connect(eth->netdev[mac->id], phy_node, + mtk_phy_link_adjust, 0, phy_mode); + if (!phydev) { + dev_err(eth->dev, "could not connect to PHY\n"); + eth->phy->phy_node[port] = NULL; + return -ENODEV; + } + + phydev->supported &= PHY_GBIT_FEATURES; + phydev->advertising = phydev->supported; + + dev_info(eth->dev, + "connected port %d to PHY at %s [uid=%08x, driver=%s]\n", + port, phydev_name(phydev), phydev->phy_id, + phydev->drv->name); + + eth->phy->phy[port] = phydev; + eth->link[port] = 0; + + return 0; +} + +static void phy_init(struct mtk_eth *eth, struct mtk_mac *mac, + struct phy_device *phy) +{ + phy_attach(eth->netdev[mac->id], phydev_name(phy), + PHY_INTERFACE_MODE_MII); + + phy->autoneg = AUTONEG_ENABLE; + phy->speed = 0; + phy->duplex = 0; + phy->supported &= PHY_BASIC_FEATURES; + phy->advertising = phy->supported | ADVERTISED_Autoneg; + + phy_start_aneg(phy); +} + +static int mtk_phy_connect(struct mtk_mac *mac) +{ + struct mtk_eth *eth = mac->hw; + int i; + + for (i = 0; i < 8; i++) { + if (eth->phy->phy_node[i]) { + if (!mac->phy_dev) { + mac->phy_dev = eth->phy->phy[i]; + mac->phy_flags = MTK_PHY_FLAG_PORT; + } + } else if (eth->mii_bus) { + struct phy_device *phy; + phy = mdiobus_get_phy(eth->mii_bus, i); + if (phy) { + phy_init(eth, mac, phy); + if (!mac->phy_dev) { + mac->phy_dev = phy; + mac->phy_flags = MTK_PHY_FLAG_ATTACH; + } + } + } + } + + return 0; +} + +static void mtk_phy_disconnect(struct mtk_mac *mac) +{ + struct mtk_eth *eth = mac->hw; + unsigned long flags; + int i; + + for (i = 0; i < 8; i++) + if (eth->phy->phy_fixed[i]) { + spin_lock_irqsave(ð->phy->lock, flags); + eth->link[i] = 0; + if (eth->soc->mdio_adjust_link) + eth->soc->mdio_adjust_link(eth, i); + spin_unlock_irqrestore(ð->phy->lock, flags); + } else if (eth->phy->phy[i]) { + phy_disconnect(eth->phy->phy[i]); + } else if (eth->mii_bus) { + struct phy_device *phy = mdiobus_get_phy(eth->mii_bus, i); + if (phy) + phy_detach(phy); + } +} + +static void mtk_phy_start(struct mtk_mac *mac) +{ + struct mtk_eth *eth = mac->hw; + unsigned long flags; + int i; + + for (i = 0; i < 8; i++) { + if (eth->phy->phy_fixed[i]) { + spin_lock_irqsave(ð->phy->lock, flags); + eth->link[i] = 1; + if (eth->soc->mdio_adjust_link) + eth->soc->mdio_adjust_link(eth, i); + spin_unlock_irqrestore(ð->phy->lock, flags); + } else if (eth->phy->phy[i]) { + phy_start(eth->phy->phy[i]); + } + } +} + +static void mtk_phy_stop(struct mtk_mac *mac) +{ + struct mtk_eth *eth = mac->hw; + unsigned long flags; + int i; + + for (i = 0; i < 8; i++) + if (eth->phy->phy_fixed[i]) { + spin_lock_irqsave(ð->phy->lock, flags); + eth->link[i] = 0; + if (eth->soc->mdio_adjust_link) + eth->soc->mdio_adjust_link(eth, i); + spin_unlock_irqrestore(ð->phy->lock, flags); + } else if (eth->phy->phy[i]) { + phy_stop(eth->phy->phy[i]); + } +} + +static struct mtk_phy phy_ralink = { + .connect = mtk_phy_connect, + .disconnect = mtk_phy_disconnect, + .start = mtk_phy_start, + .stop = mtk_phy_stop, +}; + +int mtk_mdio_init(struct mtk_eth *eth) +{ + struct device_node *mii_np; + int err; + + if (!eth->soc->mdio_read || !eth->soc->mdio_write) + return 0; + + spin_lock_init(&phy_ralink.lock); + eth->phy = &phy_ralink; + + mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus"); + if (!mii_np) { + dev_err(eth->dev, "no %s child node found", "mdio-bus"); + return -ENODEV; + } + + if (!of_device_is_available(mii_np)) { + err = 0; + goto err_put_node; + } + + eth->mii_bus = mdiobus_alloc(); + if (!eth->mii_bus) { + err = -ENOMEM; + goto err_put_node; + } + + eth->mii_bus->name = "mdio"; + eth->mii_bus->read = eth->soc->mdio_read; + eth->mii_bus->write = eth->soc->mdio_write; + eth->mii_bus->reset = mtk_mdio_reset; + eth->mii_bus->priv = eth; + eth->mii_bus->parent = eth->dev; + + snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%s", mii_np->name); + err = of_mdiobus_register(eth->mii_bus, mii_np); + if (err) + goto err_free_bus; + + return 0; + +err_free_bus: + kfree(eth->mii_bus); +err_put_node: + of_node_put(mii_np); + eth->mii_bus = NULL; + return err; +} + +void mtk_mdio_cleanup(struct mtk_eth *eth) +{ + if (!eth->mii_bus) + return; + + mdiobus_unregister(eth->mii_bus); + of_node_put(eth->mii_bus->dev.of_node); + kfree(eth->mii_bus); +} diff --git a/drivers/staging/mt7621-eth/mdio.h b/drivers/staging/mt7621-eth/mdio.h new file mode 100644 index 000000000000..b14e23842a01 --- /dev/null +++ b/drivers/staging/mt7621-eth/mdio.h @@ -0,0 +1,27 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#ifndef _RALINK_MDIO_H__ +#define _RALINK_MDIO_H__ + +#ifdef CONFIG_NET_MEDIATEK_MDIO +int mtk_mdio_init(struct mtk_eth *eth); +void mtk_mdio_cleanup(struct mtk_eth *eth); +int mtk_connect_phy_node(struct mtk_eth *eth, struct mtk_mac *mac, + struct device_node *phy_node); +#else +static inline int mtk_mdio_init(struct mtk_eth *eth) { return 0; } +static inline void mtk_mdio_cleanup(struct mtk_eth *eth) {} +#endif +#endif diff --git a/drivers/staging/mt7621-eth/mdio_mt7620.c b/drivers/staging/mt7621-eth/mdio_mt7620.c new file mode 100644 index 000000000000..ced605c2914e --- /dev/null +++ b/drivers/staging/mt7621-eth/mdio_mt7620.c @@ -0,0 +1,173 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> + +#include "mtk_eth_soc.h" +#include "gsw_mt7620.h" +#include "mdio.h" + +static int mt7620_mii_busy_wait(struct mt7620_gsw *gsw) +{ + unsigned long t_start = jiffies; + + while (1) { + if (!(mtk_switch_r32(gsw, + gsw->piac_offset + MT7620_GSW_REG_PIAC) & + GSW_MDIO_ACCESS)) + return 0; + if (time_after(jiffies, t_start + GSW_REG_PHY_TIMEOUT)) + break; + } + + dev_err(gsw->dev, "mdio: MDIO timeout\n"); + return -1; +} + +u32 _mt7620_mii_write(struct mt7620_gsw *gsw, u32 phy_addr, + u32 phy_register, u32 write_data) +{ + if (mt7620_mii_busy_wait(gsw)) + return -1; + + write_data &= 0xffff; + + mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_WRITE | + (phy_register << GSW_MDIO_REG_SHIFT) | + (phy_addr << GSW_MDIO_ADDR_SHIFT) | write_data, + MT7620_GSW_REG_PIAC); + + if (mt7620_mii_busy_wait(gsw)) + return -1; + + return 0; +} +EXPORT_SYMBOL_GPL(_mt7620_mii_write); + +u32 _mt7620_mii_read(struct mt7620_gsw *gsw, int phy_addr, int phy_reg) +{ + u32 d; + + if (mt7620_mii_busy_wait(gsw)) + return 0xffff; + + mtk_switch_w32(gsw, GSW_MDIO_ACCESS | GSW_MDIO_START | GSW_MDIO_READ | + (phy_reg << GSW_MDIO_REG_SHIFT) | + (phy_addr << GSW_MDIO_ADDR_SHIFT), + MT7620_GSW_REG_PIAC); + + if (mt7620_mii_busy_wait(gsw)) + return 0xffff; + + d = mtk_switch_r32(gsw, MT7620_GSW_REG_PIAC) & 0xffff; + + return d; +} +EXPORT_SYMBOL_GPL(_mt7620_mii_read); + +int mt7620_mdio_write(struct mii_bus *bus, int phy_addr, int phy_reg, u16 val) +{ + struct mtk_eth *eth = bus->priv; + struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv; + + return _mt7620_mii_write(gsw, phy_addr, phy_reg, val); +} + +int mt7620_mdio_read(struct mii_bus *bus, int phy_addr, int phy_reg) +{ + struct mtk_eth *eth = bus->priv; + struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv; + + return _mt7620_mii_read(gsw, phy_addr, phy_reg); +} + +void mt7530_mdio_w32(struct mt7620_gsw *gsw, u32 reg, u32 val) +{ + _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff); + _mt7620_mii_write(gsw, 0x1f, (reg >> 2) & 0xf, val & 0xffff); + _mt7620_mii_write(gsw, 0x1f, 0x10, val >> 16); +} +EXPORT_SYMBOL_GPL(mt7530_mdio_w32); + +u32 mt7530_mdio_r32(struct mt7620_gsw *gsw, u32 reg) +{ + u16 high, low; + + _mt7620_mii_write(gsw, 0x1f, 0x1f, (reg >> 6) & 0x3ff); + low = _mt7620_mii_read(gsw, 0x1f, (reg >> 2) & 0xf); + high = _mt7620_mii_read(gsw, 0x1f, 0x10); + + return (high << 16) | (low & 0xffff); +} +EXPORT_SYMBOL_GPL(mt7530_mdio_r32); + +void mt7530_mdio_m32(struct mt7620_gsw *gsw, u32 mask, u32 set, u32 reg) +{ + u32 val = mt7530_mdio_r32(gsw, reg); + + val &= ~mask; + val |= set; + mt7530_mdio_w32(gsw, reg, val); +} +EXPORT_SYMBOL_GPL(mt7530_mdio_m32); + +static unsigned char *mtk_speed_str(int speed) +{ + switch (speed) { + case 2: + case SPEED_1000: + return "1000"; + case 1: + case SPEED_100: + return "100"; + case 0: + case SPEED_10: + return "10"; + } + + return "? "; +} + +int mt7620_has_carrier(struct mtk_eth *eth) +{ + struct mt7620_gsw *gsw = (struct mt7620_gsw *)eth->sw_priv; + int i; + + for (i = 0; i < GSW_PORT6; i++) + if (mt7530_mdio_r32(gsw, GSW_REG_PORT_STATUS(i)) & 0x1) + return 1; + return 0; +} + +void mt7620_print_link_state(struct mtk_eth *eth, int port, int link, + int speed, int duplex) +{ + struct mt7620_gsw *gsw = eth->sw_priv; + + if (link) + dev_info(gsw->dev, "port %d link up (%sMbps/%s duplex)\n", + port, mtk_speed_str(speed), + (duplex) ? "Full" : "Half"); + else + dev_info(gsw->dev, "port %d link down\n", port); +} + +void mt7620_mdio_link_adjust(struct mtk_eth *eth, int port) +{ + mt7620_print_link_state(eth, port, eth->link[port], + eth->phy->speed[port], + (eth->phy->duplex[port] == DUPLEX_FULL)); +} diff --git a/drivers/staging/mt7621-eth/mtk_eth_soc.c b/drivers/staging/mt7621-eth/mtk_eth_soc.c new file mode 100644 index 000000000000..cbc7339843a5 --- /dev/null +++ b/drivers/staging/mt7621-eth/mtk_eth_soc.c @@ -0,0 +1,2178 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/skbuff.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/platform_device.h> +#include <linux/of_device.h> +#include <linux/mfd/syscon.h> +#include <linux/clk.h> +#include <linux/of_net.h> +#include <linux/of_mdio.h> +#include <linux/if_vlan.h> +#include <linux/reset.h> +#include <linux/tcp.h> +#include <linux/io.h> +#include <linux/bug.h> +#include <linux/regmap.h> + +#include "mtk_eth_soc.h" +#include "mdio.h" +#include "ethtool.h" + +#define MAX_RX_LENGTH 1536 +#define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) +#define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) +#define DMA_DUMMY_DESC 0xffffffff +#define MTK_DEFAULT_MSG_ENABLE \ + (NETIF_MSG_DRV | \ + NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | \ + NETIF_MSG_TIMER | \ + NETIF_MSG_IFDOWN | \ + NETIF_MSG_IFUP | \ + NETIF_MSG_RX_ERR | \ + NETIF_MSG_TX_ERR) + +#define TX_DMA_DESP2_DEF (TX_DMA_LS0 | TX_DMA_DONE) +#define NEXT_TX_DESP_IDX(X) (((X) + 1) & (ring->tx_ring_size - 1)) +#define NEXT_RX_DESP_IDX(X) (((X) + 1) & (ring->rx_ring_size - 1)) + +#define SYSC_REG_RSTCTRL 0x34 + +static int mtk_msg_level = -1; +module_param_named(msg_level, mtk_msg_level, int, 0); +MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)"); + +static const u16 mtk_reg_table_default[MTK_REG_COUNT] = { + [MTK_REG_PDMA_GLO_CFG] = MTK_PDMA_GLO_CFG, + [MTK_REG_PDMA_RST_CFG] = MTK_PDMA_RST_CFG, + [MTK_REG_DLY_INT_CFG] = MTK_DLY_INT_CFG, + [MTK_REG_TX_BASE_PTR0] = MTK_TX_BASE_PTR0, + [MTK_REG_TX_MAX_CNT0] = MTK_TX_MAX_CNT0, + [MTK_REG_TX_CTX_IDX0] = MTK_TX_CTX_IDX0, + [MTK_REG_TX_DTX_IDX0] = MTK_TX_DTX_IDX0, + [MTK_REG_RX_BASE_PTR0] = MTK_RX_BASE_PTR0, + [MTK_REG_RX_MAX_CNT0] = MTK_RX_MAX_CNT0, + [MTK_REG_RX_CALC_IDX0] = MTK_RX_CALC_IDX0, + [MTK_REG_RX_DRX_IDX0] = MTK_RX_DRX_IDX0, + [MTK_REG_MTK_INT_ENABLE] = MTK_INT_ENABLE, + [MTK_REG_MTK_INT_STATUS] = MTK_INT_STATUS, + [MTK_REG_MTK_DMA_VID_BASE] = MTK_DMA_VID0, + [MTK_REG_MTK_COUNTER_BASE] = MTK_GDMA1_TX_GBCNT, + [MTK_REG_MTK_RST_GL] = MTK_RST_GL, +}; + +static const u16 *mtk_reg_table = mtk_reg_table_default; + +void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) +{ + __raw_writel(val, eth->base + reg); +} + +u32 mtk_r32(struct mtk_eth *eth, unsigned reg) +{ + return __raw_readl(eth->base + reg); +} + +static void mtk_reg_w32(struct mtk_eth *eth, u32 val, enum mtk_reg reg) +{ + mtk_w32(eth, val, mtk_reg_table[reg]); +} + +static u32 mtk_reg_r32(struct mtk_eth *eth, enum mtk_reg reg) +{ + return mtk_r32(eth, mtk_reg_table[reg]); +} + +/* these bits are also exposed via the reset-controller API. however the switch + * and FE need to be brought out of reset in the exakt same moemtn and the + * reset-controller api does not provide this feature yet. Do the reset manually + * until we fixed the reset-controller api to be able to do this + */ +void mtk_reset(struct mtk_eth *eth, u32 reset_bits) +{ + u32 val; + + regmap_read(eth->ethsys, SYSC_REG_RSTCTRL, &val); + val |= reset_bits; + regmap_write(eth->ethsys, SYSC_REG_RSTCTRL, val); + usleep_range(10, 20); + val &= ~reset_bits; + regmap_write(eth->ethsys, SYSC_REG_RSTCTRL, val); + usleep_range(10, 20); +} +EXPORT_SYMBOL(mtk_reset); + +static inline void mtk_irq_ack(struct mtk_eth *eth, u32 mask) +{ + if (eth->soc->dma_type & MTK_PDMA) + mtk_reg_w32(eth, mask, MTK_REG_MTK_INT_STATUS); + if (eth->soc->dma_type & MTK_QDMA) + mtk_w32(eth, mask, MTK_QMTK_INT_STATUS); +} + +static inline u32 mtk_irq_pending(struct mtk_eth *eth) +{ + u32 status = 0; + + if (eth->soc->dma_type & MTK_PDMA) + status |= mtk_reg_r32(eth, MTK_REG_MTK_INT_STATUS); + if (eth->soc->dma_type & MTK_QDMA) + status |= mtk_r32(eth, MTK_QMTK_INT_STATUS); + + return status; +} + +static void mtk_irq_ack_status(struct mtk_eth *eth, u32 mask) +{ + u32 status_reg = MTK_REG_MTK_INT_STATUS; + + if (mtk_reg_table[MTK_REG_MTK_INT_STATUS2]) + status_reg = MTK_REG_MTK_INT_STATUS2; + + mtk_reg_w32(eth, mask, status_reg); +} + +static u32 mtk_irq_pending_status(struct mtk_eth *eth) +{ + u32 status_reg = MTK_REG_MTK_INT_STATUS; + + if (mtk_reg_table[MTK_REG_MTK_INT_STATUS2]) + status_reg = MTK_REG_MTK_INT_STATUS2; + + return mtk_reg_r32(eth, status_reg); +} + +static inline void mtk_irq_disable(struct mtk_eth *eth, u32 mask) +{ + u32 val; + + if (eth->soc->dma_type & MTK_PDMA) { + val = mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE); + mtk_reg_w32(eth, val & ~mask, MTK_REG_MTK_INT_ENABLE); + /* flush write */ + mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE); + } + if (eth->soc->dma_type & MTK_QDMA) { + val = mtk_r32(eth, MTK_QMTK_INT_ENABLE); + mtk_w32(eth, val & ~mask, MTK_QMTK_INT_ENABLE); + /* flush write */ + mtk_r32(eth, MTK_QMTK_INT_ENABLE); + } +} + +static inline void mtk_irq_enable(struct mtk_eth *eth, u32 mask) +{ + u32 val; + + if (eth->soc->dma_type & MTK_PDMA) { + val = mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE); + mtk_reg_w32(eth, val | mask, MTK_REG_MTK_INT_ENABLE); + /* flush write */ + mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE); + } + if (eth->soc->dma_type & MTK_QDMA) { + val = mtk_r32(eth, MTK_QMTK_INT_ENABLE); + mtk_w32(eth, val | mask, MTK_QMTK_INT_ENABLE); + /* flush write */ + mtk_r32(eth, MTK_QMTK_INT_ENABLE); + } +} + +static inline u32 mtk_irq_enabled(struct mtk_eth *eth) +{ + u32 enabled = 0; + + if (eth->soc->dma_type & MTK_PDMA) + enabled |= mtk_reg_r32(eth, MTK_REG_MTK_INT_ENABLE); + if (eth->soc->dma_type & MTK_QDMA) + enabled |= mtk_r32(eth, MTK_QMTK_INT_ENABLE); + + return enabled; +} + +static inline void mtk_hw_set_macaddr(struct mtk_mac *mac, + unsigned char *macaddr) +{ + unsigned long flags; + + spin_lock_irqsave(&mac->hw->page_lock, flags); + mtk_w32(mac->hw, (macaddr[0] << 8) | macaddr[1], MTK_GDMA1_MAC_ADRH); + mtk_w32(mac->hw, (macaddr[2] << 24) | (macaddr[3] << 16) | + (macaddr[4] << 8) | macaddr[5], + MTK_GDMA1_MAC_ADRL); + spin_unlock_irqrestore(&mac->hw->page_lock, flags); +} + +static int mtk_set_mac_address(struct net_device *dev, void *p) +{ + int ret = eth_mac_addr(dev, p); + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + + if (ret) + return ret; + + if (eth->soc->set_mac) + eth->soc->set_mac(mac, dev->dev_addr); + else + mtk_hw_set_macaddr(mac, p); + + return 0; +} + +static inline int mtk_max_frag_size(int mtu) +{ + /* make sure buf_size will be at least MAX_RX_LENGTH */ + if (mtu + MTK_RX_ETH_HLEN < MAX_RX_LENGTH) + mtu = MAX_RX_LENGTH - MTK_RX_ETH_HLEN; + + return SKB_DATA_ALIGN(MTK_RX_HLEN + mtu) + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); +} + +static inline int mtk_max_buf_size(int frag_size) +{ + int buf_size = frag_size - NET_SKB_PAD - NET_IP_ALIGN - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + WARN_ON(buf_size < MAX_RX_LENGTH); + + return buf_size; +} + +static inline void mtk_get_rxd(struct mtk_rx_dma *rxd, + struct mtk_rx_dma *dma_rxd) +{ + rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); + rxd->rxd2 = READ_ONCE(dma_rxd->rxd2); + rxd->rxd3 = READ_ONCE(dma_rxd->rxd3); + rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); +} + +static inline void mtk_set_txd_pdma(struct mtk_tx_dma *txd, + struct mtk_tx_dma *dma_txd) +{ + WRITE_ONCE(dma_txd->txd1, txd->txd1); + WRITE_ONCE(dma_txd->txd3, txd->txd3); + WRITE_ONCE(dma_txd->txd4, txd->txd4); + /* clean dma done flag last */ + WRITE_ONCE(dma_txd->txd2, txd->txd2); +} + +static void mtk_clean_rx(struct mtk_eth *eth, struct mtk_rx_ring *ring) +{ + int i; + + if (ring->rx_data && ring->rx_dma) { + for (i = 0; i < ring->rx_ring_size; i++) { + if (!ring->rx_data[i]) + continue; + if (!ring->rx_dma[i].rxd1) + continue; + dma_unmap_single(eth->dev, + ring->rx_dma[i].rxd1, + ring->rx_buf_size, + DMA_FROM_DEVICE); + skb_free_frag(ring->rx_data[i]); + } + kfree(ring->rx_data); + ring->rx_data = NULL; + } + + if (ring->rx_dma) { + dma_free_coherent(eth->dev, + ring->rx_ring_size * sizeof(*ring->rx_dma), + ring->rx_dma, + ring->rx_phys); + ring->rx_dma = NULL; + } +} + +static int mtk_dma_rx_alloc(struct mtk_eth *eth, struct mtk_rx_ring *ring) +{ + int i, pad = 0; + + ring->frag_size = mtk_max_frag_size(ETH_DATA_LEN); + ring->rx_buf_size = mtk_max_buf_size(ring->frag_size); + ring->rx_ring_size = eth->soc->dma_ring_size; + ring->rx_data = kcalloc(ring->rx_ring_size, sizeof(*ring->rx_data), + GFP_KERNEL); + if (!ring->rx_data) + goto no_rx_mem; + + for (i = 0; i < ring->rx_ring_size; i++) { + ring->rx_data[i] = netdev_alloc_frag(ring->frag_size); + if (!ring->rx_data[i]) + goto no_rx_mem; + } + + ring->rx_dma = dma_alloc_coherent(eth->dev, + ring->rx_ring_size * sizeof(*ring->rx_dma), + &ring->rx_phys, + GFP_ATOMIC | __GFP_ZERO); + if (!ring->rx_dma) + goto no_rx_mem; + + if (!eth->soc->rx_2b_offset) + pad = NET_IP_ALIGN; + + for (i = 0; i < ring->rx_ring_size; i++) { + dma_addr_t dma_addr = dma_map_single(eth->dev, + ring->rx_data[i] + NET_SKB_PAD + pad, + ring->rx_buf_size, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(eth->dev, dma_addr))) + goto no_rx_mem; + ring->rx_dma[i].rxd1 = (unsigned int)dma_addr; + + if (eth->soc->rx_sg_dma) + ring->rx_dma[i].rxd2 = RX_DMA_PLEN0(ring->rx_buf_size); + else + ring->rx_dma[i].rxd2 = RX_DMA_LSO; + } + ring->rx_calc_idx = ring->rx_ring_size - 1; + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + + return 0; + +no_rx_mem: + return -ENOMEM; +} + +static void mtk_txd_unmap(struct device *dev, struct mtk_tx_buf *tx_buf) +{ + if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { + dma_unmap_single(dev, + dma_unmap_addr(tx_buf, dma_addr0), + dma_unmap_len(tx_buf, dma_len0), + DMA_TO_DEVICE); + } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) { + dma_unmap_page(dev, + dma_unmap_addr(tx_buf, dma_addr0), + dma_unmap_len(tx_buf, dma_len0), + DMA_TO_DEVICE); + } + if (tx_buf->flags & MTK_TX_FLAGS_PAGE1) + dma_unmap_page(dev, + dma_unmap_addr(tx_buf, dma_addr1), + dma_unmap_len(tx_buf, dma_len1), + DMA_TO_DEVICE); + + tx_buf->flags = 0; + if (tx_buf->skb && (tx_buf->skb != (struct sk_buff *)DMA_DUMMY_DESC)) + dev_kfree_skb_any(tx_buf->skb); + tx_buf->skb = NULL; +} + +static void mtk_pdma_tx_clean(struct mtk_eth *eth) +{ + struct mtk_tx_ring *ring = ð->tx_ring; + int i; + + if (ring->tx_buf) { + for (i = 0; i < ring->tx_ring_size; i++) + mtk_txd_unmap(eth->dev, &ring->tx_buf[i]); + kfree(ring->tx_buf); + ring->tx_buf = NULL; + } + + if (ring->tx_dma) { + dma_free_coherent(eth->dev, + ring->tx_ring_size * sizeof(*ring->tx_dma), + ring->tx_dma, + ring->tx_phys); + ring->tx_dma = NULL; + } +} + +static void mtk_qdma_tx_clean(struct mtk_eth *eth) +{ + struct mtk_tx_ring *ring = ð->tx_ring; + int i; + + if (ring->tx_buf) { + for (i = 0; i < ring->tx_ring_size; i++) + mtk_txd_unmap(eth->dev, &ring->tx_buf[i]); + kfree(ring->tx_buf); + ring->tx_buf = NULL; + } + + if (ring->tx_dma) { + dma_free_coherent(eth->dev, + ring->tx_ring_size * sizeof(*ring->tx_dma), + ring->tx_dma, + ring->tx_phys); + ring->tx_dma = NULL; + } +} + +void mtk_stats_update_mac(struct mtk_mac *mac) +{ + struct mtk_hw_stats *hw_stats = mac->hw_stats; + unsigned int base = mtk_reg_table[MTK_REG_MTK_COUNTER_BASE]; + u64 stats; + + base += hw_stats->reg_offset; + + u64_stats_update_begin(&hw_stats->syncp); + + if (mac->hw->soc->new_stats) { + hw_stats->rx_bytes += mtk_r32(mac->hw, base); + stats = mtk_r32(mac->hw, base + 0x04); + if (stats) + hw_stats->rx_bytes += (stats << 32); + hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x08); + hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x10); + hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x14); + hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x18); + hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x1c); + hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x20); + hw_stats->rx_flow_control_packets += + mtk_r32(mac->hw, base + 0x24); + hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x28); + hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x2c); + hw_stats->tx_bytes += mtk_r32(mac->hw, base + 0x30); + stats = mtk_r32(mac->hw, base + 0x34); + if (stats) + hw_stats->tx_bytes += (stats << 32); + hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x38); + } else { + hw_stats->tx_bytes += mtk_r32(mac->hw, base); + hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x04); + hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x08); + hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x0c); + hw_stats->rx_bytes += mtk_r32(mac->hw, base + 0x20); + hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x24); + hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x28); + hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x2c); + hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x30); + hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x34); + hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x38); + hw_stats->rx_flow_control_packets += + mtk_r32(mac->hw, base + 0x3c); + } + + u64_stats_update_end(&hw_stats->syncp); +} + +static void mtk_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *storage) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_hw_stats *hw_stats = mac->hw_stats; + unsigned int base = mtk_reg_table[MTK_REG_MTK_COUNTER_BASE]; + unsigned int start; + + if (!base) { + netdev_stats_to_stats64(storage, &dev->stats); + return; + } + + if (netif_running(dev) && netif_device_present(dev)) { + if (spin_trylock(&hw_stats->stats_lock)) { + mtk_stats_update_mac(mac); + spin_unlock(&hw_stats->stats_lock); + } + } + + do { + start = u64_stats_fetch_begin_irq(&hw_stats->syncp); + storage->rx_packets = hw_stats->rx_packets; + storage->tx_packets = hw_stats->tx_packets; + storage->rx_bytes = hw_stats->rx_bytes; + storage->tx_bytes = hw_stats->tx_bytes; + storage->collisions = hw_stats->tx_collisions; + storage->rx_length_errors = hw_stats->rx_short_errors + + hw_stats->rx_long_errors; + storage->rx_over_errors = hw_stats->rx_overflow; + storage->rx_crc_errors = hw_stats->rx_fcs_errors; + storage->rx_errors = hw_stats->rx_checksum_errors; + storage->tx_aborted_errors = hw_stats->tx_skip; + } while (u64_stats_fetch_retry_irq(&hw_stats->syncp, start)); + + storage->tx_errors = dev->stats.tx_errors; + storage->rx_dropped = dev->stats.rx_dropped; + storage->tx_dropped = dev->stats.tx_dropped; +} + +static int mtk_vlan_rx_add_vid(struct net_device *dev, + __be16 proto, u16 vid) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + u32 idx = (vid & 0xf); + u32 vlan_cfg; + + if (!((mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE]) && + (dev->features & NETIF_F_HW_VLAN_CTAG_TX))) + return 0; + + if (test_bit(idx, ð->vlan_map)) { + netdev_warn(dev, "disable tx vlan offload\n"); + dev->wanted_features &= ~NETIF_F_HW_VLAN_CTAG_TX; + netdev_update_features(dev); + } else { + vlan_cfg = mtk_r32(eth, + mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE] + + ((idx >> 1) << 2)); + if (idx & 0x1) { + vlan_cfg &= 0xffff; + vlan_cfg |= (vid << 16); + } else { + vlan_cfg &= 0xffff0000; + vlan_cfg |= vid; + } + mtk_w32(eth, + vlan_cfg, mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE] + + ((idx >> 1) << 2)); + set_bit(idx, ð->vlan_map); + } + + return 0; +} + +static int mtk_vlan_rx_kill_vid(struct net_device *dev, + __be16 proto, u16 vid) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + u32 idx = (vid & 0xf); + + if (!((mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE]) && + (dev->features & NETIF_F_HW_VLAN_CTAG_TX))) + return 0; + + clear_bit(idx, ð->vlan_map); + + return 0; +} + +static inline u32 mtk_pdma_empty_txd(struct mtk_tx_ring *ring) +{ + barrier(); + return (u32)(ring->tx_ring_size - + ((ring->tx_next_idx - ring->tx_free_idx) & + (ring->tx_ring_size - 1))); +} + +static int mtk_skb_padto(struct sk_buff *skb, struct mtk_eth *eth) +{ + unsigned int len; + int ret; + + if (unlikely(skb->len >= VLAN_ETH_ZLEN)) + return 0; + + if (eth->soc->padding_64b && !eth->soc->padding_bug) + return 0; + + if (skb_vlan_tag_present(skb)) + len = ETH_ZLEN; + else if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) + len = VLAN_ETH_ZLEN; + else if (!eth->soc->padding_64b) + len = ETH_ZLEN; + else + return 0; + + if (skb->len >= len) + return 0; + + ret = skb_pad(skb, len - skb->len); + if (ret < 0) + return ret; + skb->len = len; + skb_set_tail_pointer(skb, len); + + return ret; +} + +static int mtk_pdma_tx_map(struct sk_buff *skb, struct net_device *dev, + int tx_num, struct mtk_tx_ring *ring, bool gso) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct skb_frag_struct *frag; + struct mtk_tx_dma txd, *ptxd; + struct mtk_tx_buf *tx_buf; + int i, j, k, frag_size, frag_map_size, offset; + dma_addr_t mapped_addr; + unsigned int nr_frags; + u32 def_txd4; + + if (mtk_skb_padto(skb, eth)) { + netif_warn(eth, tx_err, dev, "tx padding failed!\n"); + return -1; + } + + tx_buf = &ring->tx_buf[ring->tx_next_idx]; + memset(tx_buf, 0, sizeof(*tx_buf)); + memset(&txd, 0, sizeof(txd)); + nr_frags = skb_shinfo(skb)->nr_frags; + + /* init tx descriptor */ + def_txd4 = eth->soc->txd4; + txd.txd4 = def_txd4; + + if (eth->soc->mac_count > 1) + txd.txd4 |= (mac->id + 1) << TX_DMA_FPORT_SHIFT; + + if (gso) + txd.txd4 |= TX_DMA_TSO; + + /* TX Checksum offload */ + if (skb->ip_summed == CHECKSUM_PARTIAL) + txd.txd4 |= TX_DMA_CHKSUM; + + /* VLAN header offload */ + if (skb_vlan_tag_present(skb)) { + u16 tag = skb_vlan_tag_get(skb); + + txd.txd4 |= TX_DMA_INS_VLAN | + ((tag >> VLAN_PRIO_SHIFT) << 4) | + (tag & 0xF); + } + + mapped_addr = dma_map_single(&dev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&dev->dev, mapped_addr))) + return -1; + + txd.txd1 = mapped_addr; + txd.txd2 = TX_DMA_PLEN0(skb_headlen(skb)); + + tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); + dma_unmap_len_set(tx_buf, dma_len0, skb_headlen(skb)); + + /* TX SG offload */ + j = ring->tx_next_idx; + k = 0; + for (i = 0; i < nr_frags; i++) { + offset = 0; + frag = &skb_shinfo(skb)->frags[i]; + frag_size = skb_frag_size(frag); + + while (frag_size > 0) { + frag_map_size = min(frag_size, TX_DMA_BUF_LEN); + mapped_addr = skb_frag_dma_map(&dev->dev, frag, offset, + frag_map_size, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&dev->dev, mapped_addr))) + goto err_dma; + + if (k & 0x1) { + j = NEXT_TX_DESP_IDX(j); + txd.txd1 = mapped_addr; + txd.txd2 = TX_DMA_PLEN0(frag_map_size); + txd.txd4 = def_txd4; + + tx_buf = &ring->tx_buf[j]; + memset(tx_buf, 0, sizeof(*tx_buf)); + + tx_buf->flags |= MTK_TX_FLAGS_PAGE0; + dma_unmap_addr_set(tx_buf, dma_addr0, + mapped_addr); + dma_unmap_len_set(tx_buf, dma_len0, + frag_map_size); + } else { + txd.txd3 = mapped_addr; + txd.txd2 |= TX_DMA_PLEN1(frag_map_size); + + tx_buf->skb = (struct sk_buff *)DMA_DUMMY_DESC; + tx_buf->flags |= MTK_TX_FLAGS_PAGE1; + dma_unmap_addr_set(tx_buf, dma_addr1, + mapped_addr); + dma_unmap_len_set(tx_buf, dma_len1, + frag_map_size); + + if (!((i == (nr_frags - 1)) && + (frag_map_size == frag_size))) { + mtk_set_txd_pdma(&txd, + &ring->tx_dma[j]); + memset(&txd, 0, sizeof(txd)); + } + } + frag_size -= frag_map_size; + offset += frag_map_size; + k++; + } + } + + /* set last segment */ + if (k & 0x1) + txd.txd2 |= TX_DMA_LS1; + else + txd.txd2 |= TX_DMA_LS0; + mtk_set_txd_pdma(&txd, &ring->tx_dma[j]); + + /* store skb to cleanup */ + tx_buf->skb = skb; + + netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); + + ring->tx_next_idx = NEXT_TX_DESP_IDX(j); + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + atomic_set(&ring->tx_free_count, mtk_pdma_empty_txd(ring)); + + if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !skb->xmit_more) + mtk_reg_w32(eth, ring->tx_next_idx, MTK_REG_TX_CTX_IDX0); + + return 0; + +err_dma: + j = ring->tx_next_idx; + for (i = 0; i < tx_num; i++) { + ptxd = &ring->tx_dma[j]; + tx_buf = &ring->tx_buf[j]; + + /* unmap dma */ + mtk_txd_unmap(&dev->dev, tx_buf); + + ptxd->txd2 = TX_DMA_DESP2_DEF; + j = NEXT_TX_DESP_IDX(j); + } + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + return -1; +} + +/* the qdma core needs scratch memory to be setup */ +static int mtk_init_fq_dma(struct mtk_eth *eth) +{ + unsigned int phy_ring_head, phy_ring_tail; + int cnt = eth->soc->dma_ring_size; + dma_addr_t dma_addr; + int i; + + eth->scratch_ring = dma_alloc_coherent(eth->dev, + cnt * sizeof(struct mtk_tx_dma), + &phy_ring_head, + GFP_ATOMIC | __GFP_ZERO); + if (unlikely(!eth->scratch_ring)) + return -ENOMEM; + + eth->scratch_head = kcalloc(cnt, QDMA_PAGE_SIZE, + GFP_KERNEL); + dma_addr = dma_map_single(eth->dev, + eth->scratch_head, cnt * QDMA_PAGE_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(eth->dev, dma_addr))) + return -ENOMEM; + + memset(eth->scratch_ring, 0x0, sizeof(struct mtk_tx_dma) * cnt); + phy_ring_tail = phy_ring_head + (sizeof(struct mtk_tx_dma) * (cnt - 1)); + + for (i = 0; i < cnt; i++) { + eth->scratch_ring[i].txd1 = (dma_addr + (i * QDMA_PAGE_SIZE)); + if (i < cnt - 1) + eth->scratch_ring[i].txd2 = (phy_ring_head + + ((i + 1) * sizeof(struct mtk_tx_dma))); + eth->scratch_ring[i].txd3 = TX_QDMA_SDL(QDMA_PAGE_SIZE); + } + + mtk_w32(eth, phy_ring_head, MTK_QDMA_FQ_HEAD); + mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL); + mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT); + mtk_w32(eth, QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN); + + return 0; +} + +static void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) +{ + void *ret = ring->tx_dma; + + return ret + (desc - ring->tx_phys); +} + +static struct mtk_tx_dma *mtk_tx_next_qdma(struct mtk_tx_ring *ring, + struct mtk_tx_dma *txd) +{ + return mtk_qdma_phys_to_virt(ring, txd->txd2); +} + +static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, + struct mtk_tx_dma *txd) +{ + int idx = txd - ring->tx_dma; + + return &ring->tx_buf[idx]; +} + +static int mtk_qdma_tx_map(struct sk_buff *skb, struct net_device *dev, + int tx_num, struct mtk_tx_ring *ring, bool gso) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_dma *itxd, *txd; + struct mtk_tx_buf *tx_buf; + dma_addr_t mapped_addr; + unsigned int nr_frags; + int i, n_desc = 1; + u32 txd4 = eth->soc->txd4; + + itxd = ring->tx_next_free; + if (itxd == ring->tx_last_free) + return -ENOMEM; + + if (eth->soc->mac_count > 1) + txd4 |= (mac->id + 1) << TX_DMA_FPORT_SHIFT; + + tx_buf = mtk_desc_to_tx_buf(ring, itxd); + memset(tx_buf, 0, sizeof(*tx_buf)); + + if (gso) + txd4 |= TX_DMA_TSO; + + /* TX Checksum offload */ + if (skb->ip_summed == CHECKSUM_PARTIAL) + txd4 |= TX_DMA_CHKSUM; + + /* VLAN header offload */ + if (skb_vlan_tag_present(skb)) + txd4 |= TX_DMA_INS_VLAN_MT7621 | skb_vlan_tag_get(skb); + + mapped_addr = dma_map_single(&dev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&dev->dev, mapped_addr))) + return -ENOMEM; + + WRITE_ONCE(itxd->txd1, mapped_addr); + tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); + dma_unmap_len_set(tx_buf, dma_len0, skb_headlen(skb)); + + /* TX SG offload */ + txd = itxd; + nr_frags = skb_shinfo(skb)->nr_frags; + for (i = 0; i < nr_frags; i++) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + unsigned int offset = 0; + int frag_size = skb_frag_size(frag); + + while (frag_size) { + bool last_frag = false; + unsigned int frag_map_size; + + txd = mtk_tx_next_qdma(ring, txd); + if (txd == ring->tx_last_free) + goto err_dma; + + n_desc++; + frag_map_size = min(frag_size, TX_DMA_BUF_LEN); + mapped_addr = skb_frag_dma_map(&dev->dev, frag, offset, + frag_map_size, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&dev->dev, mapped_addr))) + goto err_dma; + + if (i == nr_frags - 1 && + (frag_size - frag_map_size) == 0) + last_frag = true; + + WRITE_ONCE(txd->txd1, mapped_addr); + WRITE_ONCE(txd->txd3, (QDMA_TX_SWC | + TX_DMA_PLEN0(frag_map_size) | + last_frag * TX_DMA_LS0) | + mac->id); + WRITE_ONCE(txd->txd4, 0); + + tx_buf->skb = (struct sk_buff *)DMA_DUMMY_DESC; + tx_buf = mtk_desc_to_tx_buf(ring, txd); + memset(tx_buf, 0, sizeof(*tx_buf)); + + tx_buf->flags |= MTK_TX_FLAGS_PAGE0; + dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); + dma_unmap_len_set(tx_buf, dma_len0, frag_map_size); + frag_size -= frag_map_size; + offset += frag_map_size; + } + } + + /* store skb to cleanup */ + tx_buf->skb = skb; + + WRITE_ONCE(itxd->txd4, txd4); + WRITE_ONCE(itxd->txd3, (QDMA_TX_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | + (!nr_frags * TX_DMA_LS0))); + + netdev_sent_queue(dev, skb->len); + skb_tx_timestamp(skb); + + ring->tx_next_free = mtk_tx_next_qdma(ring, txd); + atomic_sub(n_desc, &ring->tx_free_count); + + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + + if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || !skb->xmit_more) + mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); + + return 0; + +err_dma: + do { + tx_buf = mtk_desc_to_tx_buf(ring, txd); + + /* unmap dma */ + mtk_txd_unmap(&dev->dev, tx_buf); + + itxd->txd3 = TX_DMA_DESP2_DEF; + itxd = mtk_tx_next_qdma(ring, itxd); + } while (itxd != txd); + + return -ENOMEM; +} + +static inline int mtk_cal_txd_req(struct sk_buff *skb) +{ + int i, nfrags; + struct skb_frag_struct *frag; + + nfrags = 1; + if (skb_is_gso(skb)) { + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + nfrags += DIV_ROUND_UP(frag->size, TX_DMA_BUF_LEN); + } + } else { + nfrags += skb_shinfo(skb)->nr_frags; + } + + return DIV_ROUND_UP(nfrags, 2); +} + +static int mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_ring *ring = ð->tx_ring; + struct net_device_stats *stats = &dev->stats; + int tx_num; + int len = skb->len; + bool gso = false; + + tx_num = mtk_cal_txd_req(skb); + if (unlikely(atomic_read(&ring->tx_free_count) <= tx_num)) { + netif_stop_queue(dev); + netif_err(eth, tx_queued, dev, + "Tx Ring full when queue awake!\n"); + return NETDEV_TX_BUSY; + } + + /* TSO: fill MSS info in tcp checksum field */ + if (skb_is_gso(skb)) { + if (skb_cow_head(skb, 0)) { + netif_warn(eth, tx_err, dev, + "GSO expand head fail.\n"); + goto drop; + } + + if (skb_shinfo(skb)->gso_type & + (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { + gso = true; + tcp_hdr(skb)->check = htons(skb_shinfo(skb)->gso_size); + } + } + + if (ring->tx_map(skb, dev, tx_num, ring, gso) < 0) + goto drop; + + stats->tx_packets++; + stats->tx_bytes += len; + + if (unlikely(atomic_read(&ring->tx_free_count) <= ring->tx_thresh)) { + netif_stop_queue(dev); + smp_mb(); + if (unlikely(atomic_read(&ring->tx_free_count) > + ring->tx_thresh)) + netif_wake_queue(dev); + } + + return NETDEV_TX_OK; + +drop: + stats->tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static int mtk_poll_rx(struct napi_struct *napi, int budget, + struct mtk_eth *eth, u32 rx_intr) +{ + struct mtk_soc_data *soc = eth->soc; + struct mtk_rx_ring *ring = ð->rx_ring[0]; + int idx = ring->rx_calc_idx; + u32 checksum_bit; + struct sk_buff *skb; + u8 *data, *new_data; + struct mtk_rx_dma *rxd, trxd; + int done = 0, pad; + + if (eth->soc->hw_features & NETIF_F_RXCSUM) + checksum_bit = soc->checksum_bit; + else + checksum_bit = 0; + + if (eth->soc->rx_2b_offset) + pad = 0; + else + pad = NET_IP_ALIGN; + + while (done < budget) { + struct net_device *netdev; + unsigned int pktlen; + dma_addr_t dma_addr; + int mac = 0; + + idx = NEXT_RX_DESP_IDX(idx); + rxd = &ring->rx_dma[idx]; + data = ring->rx_data[idx]; + + mtk_get_rxd(&trxd, rxd); + if (!(trxd.rxd2 & RX_DMA_DONE)) + break; + + /* find out which mac the packet come from. values start at 1 */ + if (eth->soc->mac_count > 1) { + mac = (trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & + RX_DMA_FPORT_MASK; + mac--; + if (mac < 0 || mac >= eth->soc->mac_count) + goto release_desc; + } + + netdev = eth->netdev[mac]; + + /* alloc new buffer */ + new_data = napi_alloc_frag(ring->frag_size); + if (unlikely(!new_data || !netdev)) { + netdev->stats.rx_dropped++; + goto release_desc; + } + dma_addr = dma_map_single(&netdev->dev, + new_data + NET_SKB_PAD + pad, + ring->rx_buf_size, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&netdev->dev, dma_addr))) { + skb_free_frag(new_data); + goto release_desc; + } + + /* receive data */ + skb = build_skb(data, ring->frag_size); + if (unlikely(!skb)) { + put_page(virt_to_head_page(new_data)); + goto release_desc; + } + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + + dma_unmap_single(&netdev->dev, trxd.rxd1, + ring->rx_buf_size, DMA_FROM_DEVICE); + pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; + skb_put(skb, pktlen); + if (trxd.rxd4 & checksum_bit) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += pktlen; + + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && + RX_DMA_VID(trxd.rxd3)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + RX_DMA_VID(trxd.rxd3)); + napi_gro_receive(napi, skb); + + ring->rx_data[idx] = new_data; + rxd->rxd1 = (unsigned int)dma_addr; + +release_desc: + if (eth->soc->rx_sg_dma) + rxd->rxd2 = RX_DMA_PLEN0(ring->rx_buf_size); + else + rxd->rxd2 = RX_DMA_LSO; + + ring->rx_calc_idx = idx; + /* make sure that all changes to the dma ring are flushed before + * we continue + */ + wmb(); + if (eth->soc->dma_type == MTK_QDMA) + mtk_w32(eth, ring->rx_calc_idx, MTK_QRX_CRX_IDX0); + else + mtk_reg_w32(eth, ring->rx_calc_idx, + MTK_REG_RX_CALC_IDX0); + done++; + } + + if (done < budget) + mtk_irq_ack(eth, rx_intr); + + return done; +} + +static int mtk_pdma_tx_poll(struct mtk_eth *eth, int budget, bool *tx_again) +{ + struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; + int done = 0; + u32 idx, hwidx; + struct mtk_tx_ring *ring = ð->tx_ring; + unsigned int bytes = 0; + + idx = ring->tx_free_idx; + hwidx = mtk_reg_r32(eth, MTK_REG_TX_DTX_IDX0); + + while ((idx != hwidx) && budget) { + tx_buf = &ring->tx_buf[idx]; + skb = tx_buf->skb; + + if (!skb) + break; + + if (skb != (struct sk_buff *)DMA_DUMMY_DESC) { + bytes += skb->len; + done++; + budget--; + } + mtk_txd_unmap(eth->dev, tx_buf); + idx = NEXT_TX_DESP_IDX(idx); + } + ring->tx_free_idx = idx; + atomic_set(&ring->tx_free_count, mtk_pdma_empty_txd(ring)); + + /* read hw index again make sure no new tx packet */ + if (idx != hwidx || idx != mtk_reg_r32(eth, MTK_REG_TX_DTX_IDX0)) + *tx_again = 1; + + if (done) + netdev_completed_queue(*eth->netdev, done, bytes); + + return done; +} + +static int mtk_qdma_tx_poll(struct mtk_eth *eth, int budget, bool *tx_again) +{ + struct mtk_tx_ring *ring = ð->tx_ring; + struct mtk_tx_dma *desc; + struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; + int total = 0, done[MTK_MAX_DEVS]; + unsigned int bytes[MTK_MAX_DEVS]; + u32 cpu, dma; + static int condition; + int i; + + memset(done, 0, sizeof(done)); + memset(bytes, 0, sizeof(bytes)); + + cpu = mtk_r32(eth, MTK_QTX_CRX_PTR); + dma = mtk_r32(eth, MTK_QTX_DRX_PTR); + + desc = mtk_qdma_phys_to_virt(ring, cpu); + + while ((cpu != dma) && budget) { + u32 next_cpu = desc->txd2; + int mac; + + desc = mtk_tx_next_qdma(ring, desc); + if ((desc->txd3 & QDMA_TX_OWNER_CPU) == 0) + break; + + mac = (desc->txd4 >> TX_DMA_FPORT_SHIFT) & + TX_DMA_FPORT_MASK; + mac--; + + tx_buf = mtk_desc_to_tx_buf(ring, desc); + skb = tx_buf->skb; + if (!skb) { + condition = 1; + break; + } + + if (skb != (struct sk_buff *)DMA_DUMMY_DESC) { + bytes[mac] += skb->len; + done[mac]++; + budget--; + } + mtk_txd_unmap(eth->dev, tx_buf); + + ring->tx_last_free->txd2 = next_cpu; + ring->tx_last_free = desc; + atomic_inc(&ring->tx_free_count); + + cpu = next_cpu; + } + + mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); + + /* read hw index again make sure no new tx packet */ + if (cpu != dma || cpu != mtk_r32(eth, MTK_QTX_DRX_PTR)) + *tx_again = true; + + for (i = 0; i < eth->soc->mac_count; i++) { + if (!done[i]) + continue; + netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); + total += done[i]; + } + + return total; +} + +static int mtk_poll_tx(struct mtk_eth *eth, int budget, u32 tx_intr, + bool *tx_again) +{ + struct mtk_tx_ring *ring = ð->tx_ring; + struct net_device *netdev = eth->netdev[0]; + int done; + + done = eth->tx_ring.tx_poll(eth, budget, tx_again); + if (!*tx_again) + mtk_irq_ack(eth, tx_intr); + + if (!done) + return 0; + + smp_mb(); + if (unlikely(!netif_queue_stopped(netdev))) + return done; + + if (atomic_read(&ring->tx_free_count) > ring->tx_thresh) + netif_wake_queue(netdev); + + return done; +} + +static void mtk_stats_update(struct mtk_eth *eth) +{ + int i; + + for (i = 0; i < eth->soc->mac_count; i++) { + if (!eth->mac[i] || !eth->mac[i]->hw_stats) + continue; + if (spin_trylock(ð->mac[i]->hw_stats->stats_lock)) { + mtk_stats_update_mac(eth->mac[i]); + spin_unlock(ð->mac[i]->hw_stats->stats_lock); + } + } +} + +static int mtk_poll(struct napi_struct *napi, int budget) +{ + struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); + u32 status, mtk_status, mask, tx_intr, rx_intr, status_intr; + int tx_done, rx_done; + bool tx_again = false; + + status = mtk_irq_pending(eth); + mtk_status = mtk_irq_pending_status(eth); + tx_intr = eth->soc->tx_int; + rx_intr = eth->soc->rx_int; + status_intr = eth->soc->status_int; + tx_done = 0; + rx_done = 0; + tx_again = 0; + + if (status & tx_intr) + tx_done = mtk_poll_tx(eth, budget, tx_intr, &tx_again); + + if (status & rx_intr) + rx_done = mtk_poll_rx(napi, budget, eth, rx_intr); + + if (unlikely(mtk_status & status_intr)) { + mtk_stats_update(eth); + mtk_irq_ack_status(eth, status_intr); + } + + if (unlikely(netif_msg_intr(eth))) { + mask = mtk_irq_enabled(eth); + netdev_info(eth->netdev[0], + "done tx %d, rx %d, intr 0x%08x/0x%x\n", + tx_done, rx_done, status, mask); + } + + if (tx_again || rx_done == budget) + return budget; + + status = mtk_irq_pending(eth); + if (status & (tx_intr | rx_intr)) + return budget; + + napi_complete(napi); + mtk_irq_enable(eth, tx_intr | rx_intr); + + return rx_done; +} + +static int mtk_pdma_tx_alloc(struct mtk_eth *eth) +{ + int i; + struct mtk_tx_ring *ring = ð->tx_ring; + + ring->tx_ring_size = eth->soc->dma_ring_size; + ring->tx_free_idx = 0; + ring->tx_next_idx = 0; + ring->tx_thresh = max((unsigned long)ring->tx_ring_size >> 2, + MAX_SKB_FRAGS); + + ring->tx_buf = kcalloc(ring->tx_ring_size, sizeof(*ring->tx_buf), + GFP_KERNEL); + if (!ring->tx_buf) + goto no_tx_mem; + + ring->tx_dma = dma_alloc_coherent(eth->dev, + ring->tx_ring_size * sizeof(*ring->tx_dma), + &ring->tx_phys, + GFP_ATOMIC | __GFP_ZERO); + if (!ring->tx_dma) + goto no_tx_mem; + + for (i = 0; i < ring->tx_ring_size; i++) { + ring->tx_dma[i].txd2 = TX_DMA_DESP2_DEF; + ring->tx_dma[i].txd4 = eth->soc->txd4; + } + + atomic_set(&ring->tx_free_count, mtk_pdma_empty_txd(ring)); + ring->tx_map = mtk_pdma_tx_map; + ring->tx_poll = mtk_pdma_tx_poll; + ring->tx_clean = mtk_pdma_tx_clean; + + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + + mtk_reg_w32(eth, ring->tx_phys, MTK_REG_TX_BASE_PTR0); + mtk_reg_w32(eth, ring->tx_ring_size, MTK_REG_TX_MAX_CNT0); + mtk_reg_w32(eth, 0, MTK_REG_TX_CTX_IDX0); + mtk_reg_w32(eth, MTK_PST_DTX_IDX0, MTK_REG_PDMA_RST_CFG); + + return 0; + +no_tx_mem: + return -ENOMEM; +} + +static int mtk_qdma_tx_alloc_tx(struct mtk_eth *eth) +{ + struct mtk_tx_ring *ring = ð->tx_ring; + int i, sz = sizeof(*ring->tx_dma); + + ring->tx_ring_size = eth->soc->dma_ring_size; + ring->tx_buf = kcalloc(ring->tx_ring_size, sizeof(*ring->tx_buf), + GFP_KERNEL); + if (!ring->tx_buf) + goto no_tx_mem; + + ring->tx_dma = dma_alloc_coherent(eth->dev, + ring->tx_ring_size * sz, + &ring->tx_phys, + GFP_ATOMIC | __GFP_ZERO); + if (!ring->tx_dma) + goto no_tx_mem; + + memset(ring->tx_dma, 0, ring->tx_ring_size * sz); + for (i = 0; i < ring->tx_ring_size; i++) { + int next = (i + 1) % ring->tx_ring_size; + u32 next_ptr = ring->tx_phys + next * sz; + + ring->tx_dma[i].txd2 = next_ptr; + ring->tx_dma[i].txd3 = TX_DMA_DESP2_DEF; + } + + atomic_set(&ring->tx_free_count, ring->tx_ring_size - 2); + ring->tx_next_free = &ring->tx_dma[0]; + ring->tx_last_free = &ring->tx_dma[ring->tx_ring_size - 2]; + ring->tx_thresh = max((unsigned long)ring->tx_ring_size >> 2, + MAX_SKB_FRAGS); + + ring->tx_map = mtk_qdma_tx_map; + ring->tx_poll = mtk_qdma_tx_poll; + ring->tx_clean = mtk_qdma_tx_clean; + + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + + mtk_w32(eth, ring->tx_phys, MTK_QTX_CTX_PTR); + mtk_w32(eth, ring->tx_phys, MTK_QTX_DTX_PTR); + mtk_w32(eth, + ring->tx_phys + ((ring->tx_ring_size - 1) * sz), + MTK_QTX_CRX_PTR); + mtk_w32(eth, + ring->tx_phys + ((ring->tx_ring_size - 1) * sz), + MTK_QTX_DRX_PTR); + + return 0; + +no_tx_mem: + return -ENOMEM; +} + +static int mtk_qdma_init(struct mtk_eth *eth, int ring) +{ + int err; + + err = mtk_init_fq_dma(eth); + if (err) + return err; + + err = mtk_qdma_tx_alloc_tx(eth); + if (err) + return err; + + err = mtk_dma_rx_alloc(eth, ð->rx_ring[ring]); + if (err) + return err; + + mtk_w32(eth, eth->rx_ring[ring].rx_phys, MTK_QRX_BASE_PTR0); + mtk_w32(eth, eth->rx_ring[ring].rx_ring_size, MTK_QRX_MAX_CNT0); + mtk_w32(eth, eth->rx_ring[ring].rx_calc_idx, MTK_QRX_CRX_IDX0); + mtk_w32(eth, MTK_PST_DRX_IDX0, MTK_QDMA_RST_IDX); + mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, MTK_QTX_CFG(0)); + + /* Enable random early drop and set drop threshold automatically */ + mtk_w32(eth, 0x174444, MTK_QDMA_FC_THRES); + mtk_w32(eth, 0x0, MTK_QDMA_HRED2); + + return 0; +} + +static int mtk_pdma_qdma_init(struct mtk_eth *eth) +{ + int err = mtk_qdma_init(eth, 1); + + if (err) + return err; + + err = mtk_dma_rx_alloc(eth, ð->rx_ring[0]); + if (err) + return err; + + mtk_reg_w32(eth, eth->rx_ring[0].rx_phys, MTK_REG_RX_BASE_PTR0); + mtk_reg_w32(eth, eth->rx_ring[0].rx_ring_size, MTK_REG_RX_MAX_CNT0); + mtk_reg_w32(eth, eth->rx_ring[0].rx_calc_idx, MTK_REG_RX_CALC_IDX0); + mtk_reg_w32(eth, MTK_PST_DRX_IDX0, MTK_REG_PDMA_RST_CFG); + + return 0; +} + +static int mtk_pdma_init(struct mtk_eth *eth) +{ + struct mtk_rx_ring *ring = ð->rx_ring[0]; + int err; + + err = mtk_pdma_tx_alloc(eth); + if (err) + return err; + + err = mtk_dma_rx_alloc(eth, ring); + if (err) + return err; + + mtk_reg_w32(eth, ring->rx_phys, MTK_REG_RX_BASE_PTR0); + mtk_reg_w32(eth, ring->rx_ring_size, MTK_REG_RX_MAX_CNT0); + mtk_reg_w32(eth, ring->rx_calc_idx, MTK_REG_RX_CALC_IDX0); + mtk_reg_w32(eth, MTK_PST_DRX_IDX0, MTK_REG_PDMA_RST_CFG); + + return 0; +} + +static void mtk_dma_free(struct mtk_eth *eth) +{ + int i; + + for (i = 0; i < eth->soc->mac_count; i++) + if (eth->netdev[i]) + netdev_reset_queue(eth->netdev[i]); + eth->tx_ring.tx_clean(eth); + mtk_clean_rx(eth, ð->rx_ring[0]); + mtk_clean_rx(eth, ð->rx_ring[1]); + kfree(eth->scratch_head); +} + +static void mtk_tx_timeout(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_ring *ring = ð->tx_ring; + + eth->netdev[mac->id]->stats.tx_errors++; + netif_err(eth, tx_err, dev, + "transmit timed out\n"); + if (eth->soc->dma_type & MTK_PDMA) { + netif_info(eth, drv, dev, "pdma_cfg:%08x\n", + mtk_reg_r32(eth, MTK_REG_PDMA_GLO_CFG)); + netif_info(eth, drv, dev, "tx_ring=%d, " + "base=%08x, max=%u, ctx=%u, dtx=%u, fdx=%hu, next=%hu\n", + 0, mtk_reg_r32(eth, MTK_REG_TX_BASE_PTR0), + mtk_reg_r32(eth, MTK_REG_TX_MAX_CNT0), + mtk_reg_r32(eth, MTK_REG_TX_CTX_IDX0), + mtk_reg_r32(eth, MTK_REG_TX_DTX_IDX0), + ring->tx_free_idx, + ring->tx_next_idx); + } + if (eth->soc->dma_type & MTK_QDMA) { + netif_info(eth, drv, dev, "qdma_cfg:%08x\n", + mtk_r32(eth, MTK_QDMA_GLO_CFG)); + netif_info(eth, drv, dev, "tx_ring=%d, " + "ctx=%08x, dtx=%08x, crx=%08x, drx=%08x, free=%hu\n", + 0, mtk_r32(eth, MTK_QTX_CTX_PTR), + mtk_r32(eth, MTK_QTX_DTX_PTR), + mtk_r32(eth, MTK_QTX_CRX_PTR), + mtk_r32(eth, MTK_QTX_DRX_PTR), + atomic_read(&ring->tx_free_count)); + } + netif_info(eth, drv, dev, + "rx_ring=%d, base=%08x, max=%u, calc=%u, drx=%u\n", + 0, mtk_reg_r32(eth, MTK_REG_RX_BASE_PTR0), + mtk_reg_r32(eth, MTK_REG_RX_MAX_CNT0), + mtk_reg_r32(eth, MTK_REG_RX_CALC_IDX0), + mtk_reg_r32(eth, MTK_REG_RX_DRX_IDX0)); + + schedule_work(&mac->pending_work); +} + +static irqreturn_t mtk_handle_irq(int irq, void *_eth) +{ + struct mtk_eth *eth = _eth; + u32 status, int_mask; + + status = mtk_irq_pending(eth); + if (unlikely(!status)) + return IRQ_NONE; + + int_mask = (eth->soc->rx_int | eth->soc->tx_int); + if (likely(status & int_mask)) { + if (likely(napi_schedule_prep(ð->rx_napi))) + __napi_schedule(ð->rx_napi); + } else { + mtk_irq_ack(eth, status); + } + mtk_irq_disable(eth, int_mask); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void mtk_poll_controller(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + u32 int_mask = eth->soc->tx_int | eth->soc->rx_int; + + mtk_irq_disable(eth, int_mask); + mtk_handle_irq(dev->irq, dev); + mtk_irq_enable(eth, int_mask); +} +#endif + +int mtk_set_clock_cycle(struct mtk_eth *eth) +{ + unsigned long sysclk = eth->sysclk; + + sysclk /= MTK_US_CYC_CNT_DIVISOR; + sysclk <<= MTK_US_CYC_CNT_SHIFT; + + mtk_w32(eth, (mtk_r32(eth, MTK_GLO_CFG) & + ~(MTK_US_CYC_CNT_MASK << MTK_US_CYC_CNT_SHIFT)) | + sysclk, + MTK_GLO_CFG); + return 0; +} + +void mtk_fwd_config(struct mtk_eth *eth) +{ + u32 fwd_cfg; + + fwd_cfg = mtk_r32(eth, MTK_GDMA1_FWD_CFG); + + /* disable jumbo frame */ + if (eth->soc->jumbo_frame) + fwd_cfg &= ~MTK_GDM1_JMB_EN; + + /* set unicast/multicast/broadcast frame to cpu */ + fwd_cfg &= ~0xffff; + + mtk_w32(eth, fwd_cfg, MTK_GDMA1_FWD_CFG); +} + +void mtk_csum_config(struct mtk_eth *eth) +{ + if (eth->soc->hw_features & NETIF_F_RXCSUM) + mtk_w32(eth, mtk_r32(eth, MTK_GDMA1_FWD_CFG) | + (MTK_GDM1_ICS_EN | MTK_GDM1_TCS_EN | MTK_GDM1_UCS_EN), + MTK_GDMA1_FWD_CFG); + else + mtk_w32(eth, mtk_r32(eth, MTK_GDMA1_FWD_CFG) & + ~(MTK_GDM1_ICS_EN | MTK_GDM1_TCS_EN | MTK_GDM1_UCS_EN), + MTK_GDMA1_FWD_CFG); + if (eth->soc->hw_features & NETIF_F_IP_CSUM) + mtk_w32(eth, mtk_r32(eth, MTK_CDMA_CSG_CFG) | + (MTK_ICS_GEN_EN | MTK_TCS_GEN_EN | MTK_UCS_GEN_EN), + MTK_CDMA_CSG_CFG); + else + mtk_w32(eth, mtk_r32(eth, MTK_CDMA_CSG_CFG) & + ~(MTK_ICS_GEN_EN | MTK_TCS_GEN_EN | MTK_UCS_GEN_EN), + MTK_CDMA_CSG_CFG); +} + +static int mtk_start_dma(struct mtk_eth *eth) +{ + unsigned long flags; + u32 val; + int err; + + if (eth->soc->dma_type == MTK_PDMA) + err = mtk_pdma_init(eth); + else if (eth->soc->dma_type == MTK_QDMA) + err = mtk_qdma_init(eth, 0); + else + err = mtk_pdma_qdma_init(eth); + if (err) { + mtk_dma_free(eth); + return err; + } + + spin_lock_irqsave(ð->page_lock, flags); + + val = MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN; + if (eth->soc->rx_2b_offset) + val |= MTK_RX_2B_OFFSET; + val |= eth->soc->pdma_glo_cfg; + + if (eth->soc->dma_type & MTK_PDMA) + mtk_reg_w32(eth, val, MTK_REG_PDMA_GLO_CFG); + + if (eth->soc->dma_type & MTK_QDMA) + mtk_w32(eth, val, MTK_QDMA_GLO_CFG); + + spin_unlock_irqrestore(ð->page_lock, flags); + + return 0; +} + +static int mtk_open(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + + if (!atomic_read(ð->dma_refcnt)) { + int err = mtk_start_dma(eth); + + if (err) + return err; + + napi_enable(ð->rx_napi); + mtk_irq_enable(eth, eth->soc->tx_int | eth->soc->rx_int); + } + atomic_inc(ð->dma_refcnt); + + if (eth->phy) + eth->phy->start(mac); + + if (eth->soc->has_carrier && eth->soc->has_carrier(eth)) + netif_carrier_on(dev); + + netif_start_queue(dev); + eth->soc->fwd_config(eth); + + return 0; +} + +static void mtk_stop_dma(struct mtk_eth *eth, u32 glo_cfg) +{ + unsigned long flags; + u32 val; + int i; + + /* stop the dma enfine */ + spin_lock_irqsave(ð->page_lock, flags); + val = mtk_r32(eth, glo_cfg); + mtk_w32(eth, val & ~(MTK_TX_WB_DDONE | MTK_RX_DMA_EN | MTK_TX_DMA_EN), + glo_cfg); + spin_unlock_irqrestore(ð->page_lock, flags); + + /* wait for dma stop */ + for (i = 0; i < 10; i++) { + val = mtk_r32(eth, glo_cfg); + if (val & (MTK_TX_DMA_BUSY | MTK_RX_DMA_BUSY)) { + msleep(20); + continue; + } + break; + } +} + +static int mtk_stop(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + + netif_tx_disable(dev); + if (eth->phy) + eth->phy->stop(mac); + + if (!atomic_dec_and_test(ð->dma_refcnt)) + return 0; + + mtk_irq_disable(eth, eth->soc->tx_int | eth->soc->rx_int); + napi_disable(ð->rx_napi); + + if (eth->soc->dma_type & MTK_PDMA) + mtk_stop_dma(eth, mtk_reg_table[MTK_REG_PDMA_GLO_CFG]); + + if (eth->soc->dma_type & MTK_QDMA) + mtk_stop_dma(eth, MTK_QDMA_GLO_CFG); + + mtk_dma_free(eth); + + return 0; +} + +static int __init mtk_init_hw(struct mtk_eth *eth) +{ + int i, err; + + eth->soc->reset_fe(eth); + + if (eth->soc->switch_init) + if (eth->soc->switch_init(eth)) { + dev_err(eth->dev, "failed to initialize switch core\n"); + return -ENODEV; + } + + err = devm_request_irq(eth->dev, eth->irq, mtk_handle_irq, 0, + dev_name(eth->dev), eth); + if (err) + return err; + + err = mtk_mdio_init(eth); + if (err) + return err; + + /* disable delay and normal interrupt */ + mtk_reg_w32(eth, 0, MTK_REG_DLY_INT_CFG); + if (eth->soc->dma_type & MTK_QDMA) + mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); + mtk_irq_disable(eth, eth->soc->tx_int | eth->soc->rx_int); + + /* frame engine will push VLAN tag regarding to VIDX field in Tx desc */ + if (mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE]) + for (i = 0; i < 16; i += 2) + mtk_w32(eth, ((i + 1) << 16) + i, + mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE] + + (i * 2)); + + if (eth->soc->fwd_config(eth)) + dev_err(eth->dev, "unable to get clock\n"); + + if (mtk_reg_table[MTK_REG_MTK_RST_GL]) { + mtk_reg_w32(eth, 1, MTK_REG_MTK_RST_GL); + mtk_reg_w32(eth, 0, MTK_REG_MTK_RST_GL); + } + + return 0; +} + +static int __init mtk_init(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct device_node *port; + const char *mac_addr; + int err; + + mac_addr = of_get_mac_address(mac->of_node); + if (mac_addr) + ether_addr_copy(dev->dev_addr, mac_addr); + + /* If the mac address is invalid, use random mac address */ + if (!is_valid_ether_addr(dev->dev_addr)) { + random_ether_addr(dev->dev_addr); + dev_err(eth->dev, "generated random MAC address %pM\n", + dev->dev_addr); + dev->addr_assign_type = NET_ADDR_RANDOM; + } + mac->hw->soc->set_mac(mac, dev->dev_addr); + + if (eth->soc->port_init) + for_each_child_of_node(mac->of_node, port) + if (of_device_is_compatible(port, + "mediatek,eth-port") && + of_device_is_available(port)) + eth->soc->port_init(eth, mac, port); + + if (eth->phy) { + err = eth->phy->connect(mac); + if (err) + return err; + } + + return 0; +} + +static void mtk_uninit(struct net_device *dev) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + + if (eth->phy) + eth->phy->disconnect(mac); + mtk_mdio_cleanup(eth); + + mtk_irq_disable(eth, ~0); + free_irq(dev->irq, dev); +} + +static int mtk_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mtk_mac *mac = netdev_priv(dev); + + if (!mac->phy_dev) + return -ENODEV; + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return phy_mii_ioctl(mac->phy_dev, ifr, cmd); + default: + break; + } + + return -EOPNOTSUPP; +} + +static int mtk_change_mtu(struct net_device *dev, int new_mtu) +{ + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + int frag_size, old_mtu; + u32 fwd_cfg; + + if (!eth->soc->jumbo_frame) + return eth_change_mtu(dev, new_mtu); + + frag_size = mtk_max_frag_size(new_mtu); + if (new_mtu < 68 || frag_size > PAGE_SIZE) + return -EINVAL; + + old_mtu = dev->mtu; + dev->mtu = new_mtu; + + /* return early if the buffer sizes will not change */ + if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN) + return 0; + if (old_mtu > ETH_DATA_LEN && new_mtu > ETH_DATA_LEN) + return 0; + + if (new_mtu <= ETH_DATA_LEN) + eth->rx_ring[0].frag_size = mtk_max_frag_size(ETH_DATA_LEN); + else + eth->rx_ring[0].frag_size = PAGE_SIZE; + eth->rx_ring[0].rx_buf_size = + mtk_max_buf_size(eth->rx_ring[0].frag_size); + + if (!netif_running(dev)) + return 0; + + mtk_stop(dev); + fwd_cfg = mtk_r32(eth, MTK_GDMA1_FWD_CFG); + if (new_mtu <= ETH_DATA_LEN) { + fwd_cfg &= ~MTK_GDM1_JMB_EN; + } else { + fwd_cfg &= ~(MTK_GDM1_JMB_LEN_MASK << MTK_GDM1_JMB_LEN_SHIFT); + fwd_cfg |= (DIV_ROUND_UP(frag_size, 1024) << + MTK_GDM1_JMB_LEN_SHIFT) | MTK_GDM1_JMB_EN; + } + mtk_w32(eth, fwd_cfg, MTK_GDMA1_FWD_CFG); + + return mtk_open(dev); +} + +static void mtk_pending_work(struct work_struct *work) +{ + struct mtk_mac *mac = container_of(work, struct mtk_mac, pending_work); + struct mtk_eth *eth = mac->hw; + struct net_device *dev = eth->netdev[mac->id]; + int err; + + rtnl_lock(); + mtk_stop(dev); + + err = mtk_open(dev); + if (err) { + netif_alert(eth, ifup, dev, + "Driver up/down cycle failed, closing device.\n"); + dev_close(dev); + } + rtnl_unlock(); +} + +static int mtk_cleanup(struct mtk_eth *eth) +{ + int i; + + for (i = 0; i < eth->soc->mac_count; i++) { + struct mtk_mac *mac = netdev_priv(eth->netdev[i]); + + if (!eth->netdev[i]) + continue; + + unregister_netdev(eth->netdev[i]); + free_netdev(eth->netdev[i]); + cancel_work_sync(&mac->pending_work); + } + + return 0; +} + +static const struct net_device_ops mtk_netdev_ops = { + .ndo_init = mtk_init, + .ndo_uninit = mtk_uninit, + .ndo_open = mtk_open, + .ndo_stop = mtk_stop, + .ndo_start_xmit = mtk_start_xmit, + .ndo_set_mac_address = mtk_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = mtk_do_ioctl, + .ndo_change_mtu = mtk_change_mtu, + .ndo_tx_timeout = mtk_tx_timeout, + .ndo_get_stats64 = mtk_get_stats64, + .ndo_vlan_rx_add_vid = mtk_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = mtk_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = mtk_poll_controller, +#endif +}; + +static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +{ + struct mtk_mac *mac; + const __be32 *_id = of_get_property(np, "reg", NULL); + int id, err; + + if (!_id) { + dev_err(eth->dev, "missing mac id\n"); + return -EINVAL; + } + id = be32_to_cpup(_id); + if (id >= eth->soc->mac_count || eth->netdev[id]) { + dev_err(eth->dev, "%d is not a valid mac id\n", id); + return -EINVAL; + } + + eth->netdev[id] = alloc_etherdev(sizeof(*mac)); + if (!eth->netdev[id]) { + dev_err(eth->dev, "alloc_etherdev failed\n"); + return -ENOMEM; + } + mac = netdev_priv(eth->netdev[id]); + eth->mac[id] = mac; + mac->id = id; + mac->hw = eth; + mac->of_node = np; + INIT_WORK(&mac->pending_work, mtk_pending_work); + + if (mtk_reg_table[MTK_REG_MTK_COUNTER_BASE]) { + mac->hw_stats = devm_kzalloc(eth->dev, + sizeof(*mac->hw_stats), + GFP_KERNEL); + if (!mac->hw_stats) + return -ENOMEM; + spin_lock_init(&mac->hw_stats->stats_lock); + mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; + } + + SET_NETDEV_DEV(eth->netdev[id], eth->dev); + eth->netdev[id]->netdev_ops = &mtk_netdev_ops; + eth->netdev[id]->base_addr = (unsigned long)eth->base; + + if (eth->soc->init_data) + eth->soc->init_data(eth->soc, eth->netdev[id]); + + eth->netdev[id]->vlan_features = eth->soc->hw_features & + ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); + eth->netdev[id]->features |= eth->soc->hw_features; + + if (mtk_reg_table[MTK_REG_MTK_DMA_VID_BASE]) + eth->netdev[id]->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + + mtk_set_ethtool_ops(eth->netdev[id]); + + err = register_netdev(eth->netdev[id]); + if (err) { + dev_err(eth->dev, "error bringing up device\n"); + return err; + } + eth->netdev[id]->irq = eth->irq; + netif_info(eth, probe, eth->netdev[id], + "mediatek frame engine at 0x%08lx, irq %d\n", + eth->netdev[id]->base_addr, eth->netdev[id]->irq); + + return 0; +} + +static int mtk_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + const struct of_device_id *match; + struct device_node *mac_np; + struct mtk_soc_data *soc; + struct mtk_eth *eth; + struct clk *sysclk; + int err; + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + device_reset(&pdev->dev); + + match = of_match_device(of_mtk_match, &pdev->dev); + soc = (struct mtk_soc_data *)match->data; + + if (soc->reg_table) + mtk_reg_table = soc->reg_table; + + eth = devm_kzalloc(&pdev->dev, sizeof(*eth), GFP_KERNEL); + if (!eth) + return -ENOMEM; + + eth->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(eth->base)) + return PTR_ERR(eth->base); + + spin_lock_init(ð->page_lock); + + eth->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "mediatek,ethsys"); + if (IS_ERR(eth->ethsys)) + return PTR_ERR(eth->ethsys); + + eth->irq = platform_get_irq(pdev, 0); + if (eth->irq < 0) { + dev_err(&pdev->dev, "no IRQ resource found\n"); + return -ENXIO; + } + + sysclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sysclk)) { + dev_err(&pdev->dev, + "the clock is not defined in the devicetree\n"); + return -ENXIO; + } + eth->sysclk = clk_get_rate(sysclk); + + eth->switch_np = of_parse_phandle(pdev->dev.of_node, + "mediatek,switch", 0); + if (soc->has_switch && !eth->switch_np) { + dev_err(&pdev->dev, "failed to read switch phandle\n"); + return -ENODEV; + } + + eth->dev = &pdev->dev; + eth->soc = soc; + eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); + + err = mtk_init_hw(eth); + if (err) + return err; + + if (eth->soc->mac_count > 1) { + for_each_child_of_node(pdev->dev.of_node, mac_np) { + if (!of_device_is_compatible(mac_np, + "mediatek,eth-mac")) + continue; + + if (!of_device_is_available(mac_np)) + continue; + + err = mtk_add_mac(eth, mac_np); + if (err) + goto err_free_dev; + } + + init_dummy_netdev(ð->dummy_dev); + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_poll, + soc->napi_weight); + } else { + err = mtk_add_mac(eth, pdev->dev.of_node); + if (err) + goto err_free_dev; + netif_napi_add(eth->netdev[0], ð->rx_napi, mtk_poll, + soc->napi_weight); + } + + platform_set_drvdata(pdev, eth); + + return 0; + +err_free_dev: + mtk_cleanup(eth); + return err; +} + +static int mtk_remove(struct platform_device *pdev) +{ + struct mtk_eth *eth = platform_get_drvdata(pdev); + + netif_napi_del(ð->rx_napi); + mtk_cleanup(eth); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver mtk_driver = { + .probe = mtk_probe, + .remove = mtk_remove, + .driver = { + .name = "mtk_soc_eth", + .owner = THIS_MODULE, + .of_match_table = of_mtk_match, + }, +}; + +module_platform_driver(mtk_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +MODULE_DESCRIPTION("Ethernet driver for MediaTek SoC"); diff --git a/drivers/staging/mt7621-eth/mtk_eth_soc.h b/drivers/staging/mt7621-eth/mtk_eth_soc.h new file mode 100644 index 000000000000..443f88d8af65 --- /dev/null +++ b/drivers/staging/mt7621-eth/mtk_eth_soc.h @@ -0,0 +1,721 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#ifndef MTK_ETH_H +#define MTK_ETH_H + +#include <linux/mii.h> +#include <linux/interrupt.h> +#include <linux/netdevice.h> +#include <linux/dma-mapping.h> +#include <linux/phy.h> +#include <linux/ethtool.h> +#include <linux/version.h> +#include <linux/atomic.h> + +/* these registers have different offsets depending on the SoC. we use a lookup + * table for these + */ +enum mtk_reg { + MTK_REG_PDMA_GLO_CFG = 0, + MTK_REG_PDMA_RST_CFG, + MTK_REG_DLY_INT_CFG, + MTK_REG_TX_BASE_PTR0, + MTK_REG_TX_MAX_CNT0, + MTK_REG_TX_CTX_IDX0, + MTK_REG_TX_DTX_IDX0, + MTK_REG_RX_BASE_PTR0, + MTK_REG_RX_MAX_CNT0, + MTK_REG_RX_CALC_IDX0, + MTK_REG_RX_DRX_IDX0, + MTK_REG_MTK_INT_ENABLE, + MTK_REG_MTK_INT_STATUS, + MTK_REG_MTK_DMA_VID_BASE, + MTK_REG_MTK_COUNTER_BASE, + MTK_REG_MTK_RST_GL, + MTK_REG_MTK_INT_STATUS2, + MTK_REG_COUNT +}; + +/* delayed interrupt bits */ +#define MTK_DELAY_EN_INT 0x80 +#define MTK_DELAY_MAX_INT 0x04 +#define MTK_DELAY_MAX_TOUT 0x04 +#define MTK_DELAY_TIME 20 +#define MTK_DELAY_CHAN (((MTK_DELAY_EN_INT | MTK_DELAY_MAX_INT) << 8) \ + | MTK_DELAY_MAX_TOUT) +#define MTK_DELAY_INIT ((MTK_DELAY_CHAN << 16) | MTK_DELAY_CHAN) +#define MTK_PSE_FQFC_CFG_INIT 0x80504000 +#define MTK_PSE_FQFC_CFG_256Q 0xff908000 + +/* interrupt bits */ +#define MTK_CNT_PPE_AF BIT(31) +#define MTK_CNT_GDM_AF BIT(29) +#define MTK_PSE_P2_FC BIT(26) +#define MTK_PSE_BUF_DROP BIT(24) +#define MTK_GDM_OTHER_DROP BIT(23) +#define MTK_PSE_P1_FC BIT(22) +#define MTK_PSE_P0_FC BIT(21) +#define MTK_PSE_FQ_EMPTY BIT(20) +#define MTK_GE1_STA_CHG BIT(18) +#define MTK_TX_COHERENT BIT(17) +#define MTK_RX_COHERENT BIT(16) +#define MTK_TX_DONE_INT3 BIT(11) +#define MTK_TX_DONE_INT2 BIT(10) +#define MTK_TX_DONE_INT1 BIT(9) +#define MTK_TX_DONE_INT0 BIT(8) +#define MTK_RX_DONE_INT0 BIT(2) +#define MTK_TX_DLY_INT BIT(1) +#define MTK_RX_DLY_INT BIT(0) + +#define MTK_RX_DONE_INT MTK_RX_DONE_INT0 +#define MTK_TX_DONE_INT (MTK_TX_DONE_INT0 | MTK_TX_DONE_INT1 | \ + MTK_TX_DONE_INT2 | MTK_TX_DONE_INT3) + +#define RT5350_RX_DLY_INT BIT(30) +#define RT5350_TX_DLY_INT BIT(28) +#define RT5350_RX_DONE_INT1 BIT(17) +#define RT5350_RX_DONE_INT0 BIT(16) +#define RT5350_TX_DONE_INT3 BIT(3) +#define RT5350_TX_DONE_INT2 BIT(2) +#define RT5350_TX_DONE_INT1 BIT(1) +#define RT5350_TX_DONE_INT0 BIT(0) + +#define RT5350_RX_DONE_INT (RT5350_RX_DONE_INT0 | RT5350_RX_DONE_INT1) +#define RT5350_TX_DONE_INT (RT5350_TX_DONE_INT0 | RT5350_TX_DONE_INT1 | \ + RT5350_TX_DONE_INT2 | RT5350_TX_DONE_INT3) + +/* registers */ +#define MTK_GDMA_OFFSET 0x0020 +#define MTK_PSE_OFFSET 0x0040 +#define MTK_GDMA2_OFFSET 0x0060 +#define MTK_CDMA_OFFSET 0x0080 +#define MTK_DMA_VID0 0x00a8 +#define MTK_PDMA_OFFSET 0x0100 +#define MTK_PPE_OFFSET 0x0200 +#define MTK_CMTABLE_OFFSET 0x0400 +#define MTK_POLICYTABLE_OFFSET 0x1000 + +#define MT7621_GDMA_OFFSET 0x0500 +#define MT7620_GDMA_OFFSET 0x0600 + +#define RT5350_PDMA_OFFSET 0x0800 +#define RT5350_SDM_OFFSET 0x0c00 + +#define MTK_MDIO_ACCESS 0x00 +#define MTK_MDIO_CFG 0x04 +#define MTK_GLO_CFG 0x08 +#define MTK_RST_GL 0x0C +#define MTK_INT_STATUS 0x10 +#define MTK_INT_ENABLE 0x14 +#define MTK_MDIO_CFG2 0x18 +#define MTK_FOC_TS_T 0x1C + +#define MTK_GDMA1_FWD_CFG (MTK_GDMA_OFFSET + 0x00) +#define MTK_GDMA1_SCH_CFG (MTK_GDMA_OFFSET + 0x04) +#define MTK_GDMA1_SHPR_CFG (MTK_GDMA_OFFSET + 0x08) +#define MTK_GDMA1_MAC_ADRL (MTK_GDMA_OFFSET + 0x0C) +#define MTK_GDMA1_MAC_ADRH (MTK_GDMA_OFFSET + 0x10) + +#define MTK_GDMA2_FWD_CFG (MTK_GDMA2_OFFSET + 0x00) +#define MTK_GDMA2_SCH_CFG (MTK_GDMA2_OFFSET + 0x04) +#define MTK_GDMA2_SHPR_CFG (MTK_GDMA2_OFFSET + 0x08) +#define MTK_GDMA2_MAC_ADRL (MTK_GDMA2_OFFSET + 0x0C) +#define MTK_GDMA2_MAC_ADRH (MTK_GDMA2_OFFSET + 0x10) + +#define MTK_PSE_FQ_CFG (MTK_PSE_OFFSET + 0x00) +#define MTK_CDMA_FC_CFG (MTK_PSE_OFFSET + 0x04) +#define MTK_GDMA1_FC_CFG (MTK_PSE_OFFSET + 0x08) +#define MTK_GDMA2_FC_CFG (MTK_PSE_OFFSET + 0x0C) + +#define MTK_CDMA_CSG_CFG (MTK_CDMA_OFFSET + 0x00) +#define MTK_CDMA_SCH_CFG (MTK_CDMA_OFFSET + 0x04) + +#define MT7621_GDMA_FWD_CFG(x) (MT7621_GDMA_OFFSET + (x * 0x1000)) + +/* FIXME this might be different for different SOCs */ +#define MT7620_GDMA1_FWD_CFG (MT7621_GDMA_OFFSET + 0x00) + +#define RT5350_TX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x00) +#define RT5350_TX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x04) +#define RT5350_TX_CTX_IDX0 (RT5350_PDMA_OFFSET + 0x08) +#define RT5350_TX_DTX_IDX0 (RT5350_PDMA_OFFSET + 0x0C) +#define RT5350_TX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x10) +#define RT5350_TX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x14) +#define RT5350_TX_CTX_IDX1 (RT5350_PDMA_OFFSET + 0x18) +#define RT5350_TX_DTX_IDX1 (RT5350_PDMA_OFFSET + 0x1C) +#define RT5350_TX_BASE_PTR2 (RT5350_PDMA_OFFSET + 0x20) +#define RT5350_TX_MAX_CNT2 (RT5350_PDMA_OFFSET + 0x24) +#define RT5350_TX_CTX_IDX2 (RT5350_PDMA_OFFSET + 0x28) +#define RT5350_TX_DTX_IDX2 (RT5350_PDMA_OFFSET + 0x2C) +#define RT5350_TX_BASE_PTR3 (RT5350_PDMA_OFFSET + 0x30) +#define RT5350_TX_MAX_CNT3 (RT5350_PDMA_OFFSET + 0x34) +#define RT5350_TX_CTX_IDX3 (RT5350_PDMA_OFFSET + 0x38) +#define RT5350_TX_DTX_IDX3 (RT5350_PDMA_OFFSET + 0x3C) +#define RT5350_RX_BASE_PTR0 (RT5350_PDMA_OFFSET + 0x100) +#define RT5350_RX_MAX_CNT0 (RT5350_PDMA_OFFSET + 0x104) +#define RT5350_RX_CALC_IDX0 (RT5350_PDMA_OFFSET + 0x108) +#define RT5350_RX_DRX_IDX0 (RT5350_PDMA_OFFSET + 0x10C) +#define RT5350_RX_BASE_PTR1 (RT5350_PDMA_OFFSET + 0x110) +#define RT5350_RX_MAX_CNT1 (RT5350_PDMA_OFFSET + 0x114) +#define RT5350_RX_CALC_IDX1 (RT5350_PDMA_OFFSET + 0x118) +#define RT5350_RX_DRX_IDX1 (RT5350_PDMA_OFFSET + 0x11C) +#define RT5350_PDMA_GLO_CFG (RT5350_PDMA_OFFSET + 0x204) +#define RT5350_PDMA_RST_CFG (RT5350_PDMA_OFFSET + 0x208) +#define RT5350_DLY_INT_CFG (RT5350_PDMA_OFFSET + 0x20c) +#define RT5350_MTK_INT_STATUS (RT5350_PDMA_OFFSET + 0x220) +#define RT5350_MTK_INT_ENABLE (RT5350_PDMA_OFFSET + 0x228) +#define RT5350_PDMA_SCH_CFG (RT5350_PDMA_OFFSET + 0x280) + +#define MTK_PDMA_GLO_CFG (MTK_PDMA_OFFSET + 0x00) +#define MTK_PDMA_RST_CFG (MTK_PDMA_OFFSET + 0x04) +#define MTK_PDMA_SCH_CFG (MTK_PDMA_OFFSET + 0x08) +#define MTK_DLY_INT_CFG (MTK_PDMA_OFFSET + 0x0C) +#define MTK_TX_BASE_PTR0 (MTK_PDMA_OFFSET + 0x10) +#define MTK_TX_MAX_CNT0 (MTK_PDMA_OFFSET + 0x14) +#define MTK_TX_CTX_IDX0 (MTK_PDMA_OFFSET + 0x18) +#define MTK_TX_DTX_IDX0 (MTK_PDMA_OFFSET + 0x1C) +#define MTK_TX_BASE_PTR1 (MTK_PDMA_OFFSET + 0x20) +#define MTK_TX_MAX_CNT1 (MTK_PDMA_OFFSET + 0x24) +#define MTK_TX_CTX_IDX1 (MTK_PDMA_OFFSET + 0x28) +#define MTK_TX_DTX_IDX1 (MTK_PDMA_OFFSET + 0x2C) +#define MTK_RX_BASE_PTR0 (MTK_PDMA_OFFSET + 0x30) +#define MTK_RX_MAX_CNT0 (MTK_PDMA_OFFSET + 0x34) +#define MTK_RX_CALC_IDX0 (MTK_PDMA_OFFSET + 0x38) +#define MTK_RX_DRX_IDX0 (MTK_PDMA_OFFSET + 0x3C) +#define MTK_TX_BASE_PTR2 (MTK_PDMA_OFFSET + 0x40) +#define MTK_TX_MAX_CNT2 (MTK_PDMA_OFFSET + 0x44) +#define MTK_TX_CTX_IDX2 (MTK_PDMA_OFFSET + 0x48) +#define MTK_TX_DTX_IDX2 (MTK_PDMA_OFFSET + 0x4C) +#define MTK_TX_BASE_PTR3 (MTK_PDMA_OFFSET + 0x50) +#define MTK_TX_MAX_CNT3 (MTK_PDMA_OFFSET + 0x54) +#define MTK_TX_CTX_IDX3 (MTK_PDMA_OFFSET + 0x58) +#define MTK_TX_DTX_IDX3 (MTK_PDMA_OFFSET + 0x5C) +#define MTK_RX_BASE_PTR1 (MTK_PDMA_OFFSET + 0x60) +#define MTK_RX_MAX_CNT1 (MTK_PDMA_OFFSET + 0x64) +#define MTK_RX_CALC_IDX1 (MTK_PDMA_OFFSET + 0x68) +#define MTK_RX_DRX_IDX1 (MTK_PDMA_OFFSET + 0x6C) + +/* Switch DMA configuration */ +#define RT5350_SDM_CFG (RT5350_SDM_OFFSET + 0x00) +#define RT5350_SDM_RRING (RT5350_SDM_OFFSET + 0x04) +#define RT5350_SDM_TRING (RT5350_SDM_OFFSET + 0x08) +#define RT5350_SDM_MAC_ADRL (RT5350_SDM_OFFSET + 0x0C) +#define RT5350_SDM_MAC_ADRH (RT5350_SDM_OFFSET + 0x10) +#define RT5350_SDM_TPCNT (RT5350_SDM_OFFSET + 0x100) +#define RT5350_SDM_TBCNT (RT5350_SDM_OFFSET + 0x104) +#define RT5350_SDM_RPCNT (RT5350_SDM_OFFSET + 0x108) +#define RT5350_SDM_RBCNT (RT5350_SDM_OFFSET + 0x10C) +#define RT5350_SDM_CS_ERR (RT5350_SDM_OFFSET + 0x110) + +#define RT5350_SDM_ICS_EN BIT(16) +#define RT5350_SDM_TCS_EN BIT(17) +#define RT5350_SDM_UCS_EN BIT(18) + +/* QDMA registers */ +#define MTK_QTX_CFG(x) (0x1800 + (x * 0x10)) +#define MTK_QTX_SCH(x) (0x1804 + (x * 0x10)) +#define MTK_QRX_BASE_PTR0 0x1900 +#define MTK_QRX_MAX_CNT0 0x1904 +#define MTK_QRX_CRX_IDX0 0x1908 +#define MTK_QRX_DRX_IDX0 0x190C +#define MTK_QDMA_GLO_CFG 0x1A04 +#define MTK_QDMA_RST_IDX 0x1A08 +#define MTK_QDMA_DELAY_INT 0x1A0C +#define MTK_QDMA_FC_THRES 0x1A10 +#define MTK_QMTK_INT_STATUS 0x1A18 +#define MTK_QMTK_INT_ENABLE 0x1A1C +#define MTK_QDMA_HRED2 0x1A44 + +#define MTK_QTX_CTX_PTR 0x1B00 +#define MTK_QTX_DTX_PTR 0x1B04 + +#define MTK_QTX_CRX_PTR 0x1B10 +#define MTK_QTX_DRX_PTR 0x1B14 + +#define MTK_QDMA_FQ_HEAD 0x1B20 +#define MTK_QDMA_FQ_TAIL 0x1B24 +#define MTK_QDMA_FQ_CNT 0x1B28 +#define MTK_QDMA_FQ_BLEN 0x1B2C + +#define QDMA_PAGE_SIZE 2048 +#define QDMA_TX_OWNER_CPU BIT(31) +#define QDMA_TX_SWC BIT(14) +#define TX_QDMA_SDL(_x) (((_x) & 0x3fff) << 16) +#define QDMA_RES_THRES 4 + +/* MDIO_CFG register bits */ +#define MTK_MDIO_CFG_AUTO_POLL_EN BIT(29) +#define MTK_MDIO_CFG_GP1_BP_EN BIT(16) +#define MTK_MDIO_CFG_GP1_FRC_EN BIT(15) +#define MTK_MDIO_CFG_GP1_SPEED_10 (0 << 13) +#define MTK_MDIO_CFG_GP1_SPEED_100 (1 << 13) +#define MTK_MDIO_CFG_GP1_SPEED_1000 (2 << 13) +#define MTK_MDIO_CFG_GP1_DUPLEX BIT(12) +#define MTK_MDIO_CFG_GP1_FC_TX BIT(11) +#define MTK_MDIO_CFG_GP1_FC_RX BIT(10) +#define MTK_MDIO_CFG_GP1_LNK_DWN BIT(9) +#define MTK_MDIO_CFG_GP1_AN_FAIL BIT(8) +#define MTK_MDIO_CFG_MDC_CLK_DIV_1 (0 << 6) +#define MTK_MDIO_CFG_MDC_CLK_DIV_2 (1 << 6) +#define MTK_MDIO_CFG_MDC_CLK_DIV_4 (2 << 6) +#define MTK_MDIO_CFG_MDC_CLK_DIV_8 (3 << 6) +#define MTK_MDIO_CFG_TURBO_MII_FREQ BIT(5) +#define MTK_MDIO_CFG_TURBO_MII_MODE BIT(4) +#define MTK_MDIO_CFG_RX_CLK_SKEW_0 (0 << 2) +#define MTK_MDIO_CFG_RX_CLK_SKEW_200 (1 << 2) +#define MTK_MDIO_CFG_RX_CLK_SKEW_400 (2 << 2) +#define MTK_MDIO_CFG_RX_CLK_SKEW_INV (3 << 2) +#define MTK_MDIO_CFG_TX_CLK_SKEW_0 0 +#define MTK_MDIO_CFG_TX_CLK_SKEW_200 1 +#define MTK_MDIO_CFG_TX_CLK_SKEW_400 2 +#define MTK_MDIO_CFG_TX_CLK_SKEW_INV 3 + +/* uni-cast port */ +#define MTK_GDM1_JMB_LEN_MASK 0xf +#define MTK_GDM1_JMB_LEN_SHIFT 28 +#define MTK_GDM1_ICS_EN BIT(22) +#define MTK_GDM1_TCS_EN BIT(21) +#define MTK_GDM1_UCS_EN BIT(20) +#define MTK_GDM1_JMB_EN BIT(19) +#define MTK_GDM1_STRPCRC BIT(16) +#define MTK_GDM1_UFRC_P_CPU (0 << 12) +#define MTK_GDM1_UFRC_P_GDMA1 (1 << 12) +#define MTK_GDM1_UFRC_P_PPE (6 << 12) + +/* checksums */ +#define MTK_ICS_GEN_EN BIT(2) +#define MTK_UCS_GEN_EN BIT(1) +#define MTK_TCS_GEN_EN BIT(0) + +/* dma mode */ +#define MTK_PDMA BIT(0) +#define MTK_QDMA BIT(1) +#define MTK_PDMA_RX_QDMA_TX (MTK_PDMA | MTK_QDMA) + +/* dma ring */ +#define MTK_PST_DRX_IDX0 BIT(16) +#define MTK_PST_DTX_IDX3 BIT(3) +#define MTK_PST_DTX_IDX2 BIT(2) +#define MTK_PST_DTX_IDX1 BIT(1) +#define MTK_PST_DTX_IDX0 BIT(0) + +#define MTK_RX_2B_OFFSET BIT(31) +#define MTK_TX_WB_DDONE BIT(6) +#define MTK_RX_DMA_BUSY BIT(3) +#define MTK_TX_DMA_BUSY BIT(1) +#define MTK_RX_DMA_EN BIT(2) +#define MTK_TX_DMA_EN BIT(0) + +#define MTK_PDMA_SIZE_4DWORDS (0 << 4) +#define MTK_PDMA_SIZE_8DWORDS (1 << 4) +#define MTK_PDMA_SIZE_16DWORDS (2 << 4) + +#define MTK_US_CYC_CNT_MASK 0xff +#define MTK_US_CYC_CNT_SHIFT 0x8 +#define MTK_US_CYC_CNT_DIVISOR 1000000 + +/* PDMA descriptor rxd2 */ +#define RX_DMA_DONE BIT(31) +#define RX_DMA_LSO BIT(30) +#define RX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16) +#define RX_DMA_GET_PLEN0(_x) (((_x) >> 16) & 0x3fff) +#define RX_DMA_TAG BIT(15) + +/* PDMA descriptor rxd3 */ +#define RX_DMA_TPID(_x) (((_x) >> 16) & 0xffff) +#define RX_DMA_VID(_x) ((_x) & 0xfff) + +/* PDMA descriptor rxd4 */ +#define RX_DMA_L4VALID BIT(30) +#define RX_DMA_FPORT_SHIFT 19 +#define RX_DMA_FPORT_MASK 0x7 + +struct mtk_rx_dma { + unsigned int rxd1; + unsigned int rxd2; + unsigned int rxd3; + unsigned int rxd4; +} __packed __aligned(4); + +/* PDMA tx descriptor bits */ +#define TX_DMA_BUF_LEN 0x3fff +#define TX_DMA_PLEN0_MASK (TX_DMA_BUF_LEN << 16) +#define TX_DMA_PLEN0(_x) (((_x) & TX_DMA_BUF_LEN) << 16) +#define TX_DMA_PLEN1(_x) ((_x) & TX_DMA_BUF_LEN) +#define TX_DMA_GET_PLEN0(_x) (((_x) >> 16) & TX_DMA_BUF_LEN) +#define TX_DMA_GET_PLEN1(_x) ((_x) & TX_DMA_BUF_LEN) +#define TX_DMA_LS1 BIT(14) +#define TX_DMA_LS0 BIT(30) +#define TX_DMA_DONE BIT(31) +#define TX_DMA_FPORT_SHIFT 25 +#define TX_DMA_FPORT_MASK 0x7 +#define TX_DMA_INS_VLAN_MT7621 BIT(16) +#define TX_DMA_INS_VLAN BIT(7) +#define TX_DMA_INS_PPPOE BIT(12) +#define TX_DMA_TAG BIT(15) +#define TX_DMA_TAG_MASK BIT(15) +#define TX_DMA_QN(_x) ((_x) << 16) +#define TX_DMA_PN(_x) ((_x) << 24) +#define TX_DMA_QN_MASK TX_DMA_QN(0x7) +#define TX_DMA_PN_MASK TX_DMA_PN(0x7) +#define TX_DMA_UDF BIT(20) +#define TX_DMA_CHKSUM (0x7 << 29) +#define TX_DMA_TSO BIT(28) +#define TX_DMA_DESP4_DEF (TX_DMA_QN(3) | TX_DMA_PN(1)) + +/* frame engine counters */ +#define MTK_PPE_AC_BCNT0 (MTK_CMTABLE_OFFSET + 0x00) +#define MTK_GDMA1_TX_GBCNT (MTK_CMTABLE_OFFSET + 0x300) +#define MTK_GDMA2_TX_GBCNT (MTK_GDMA1_TX_GBCNT + 0x40) + +/* phy device flags */ +#define MTK_PHY_FLAG_PORT BIT(0) +#define MTK_PHY_FLAG_ATTACH BIT(1) + +struct mtk_tx_dma { + unsigned int txd1; + unsigned int txd2; + unsigned int txd3; + unsigned int txd4; +} __packed __aligned(4); + +struct mtk_eth; +struct mtk_mac; + +/* manage the attached phys */ +struct mtk_phy { + spinlock_t lock; + + struct phy_device *phy[8]; + struct device_node *phy_node[8]; + const __be32 *phy_fixed[8]; + int duplex[8]; + int speed[8]; + int tx_fc[8]; + int rx_fc[8]; + int (*connect)(struct mtk_mac *mac); + void (*disconnect)(struct mtk_mac *mac); + void (*start)(struct mtk_mac *mac); + void (*stop)(struct mtk_mac *mac); +}; + +/* struct mtk_soc_data - the structure that holds the SoC specific data + * @reg_table: Some of the legacy registers changed their location + * over time. Their offsets are stored in this table + * + * @init_data: Some features depend on the silicon revision. This + * callback allows runtime modification of the content of + * this struct + * @reset_fe: This callback is used to trigger the reset of the frame + * engine + * @set_mac: This callback is used to set the unicast mac address + * filter + * @fwd_config: This callback is used to setup the forward config + * register of the MAC + * @switch_init: This callback is used to bring up the switch core + * @port_init: Some SoCs have ports that can be router to a switch port + * or an external PHY. This callback is used to setup these + * ports. + * @has_carrier: This callback allows driver to check if there is a cable + * attached. + * @mdio_init: This callbck is used to setup the MDIO bus if one is + * present + * @mdio_cleanup: This callback is used to cleanup the MDIO state. + * @mdio_write: This callback is used to write data to the MDIO bus. + * @mdio_read: This callback is used to write data to the MDIO bus. + * @mdio_adjust_link: This callback is used to apply the PHY settings. + * @piac_offset: the PIAC register has a different different base offset + * @hw_features: feature set depends on the SoC type + * @dma_ring_size: allow GBit SoCs to set bigger rings than FE SoCs + * @napi_weight: allow GBit SoCs to set bigger napi weight than FE SoCs + * @dma_type: SoCs is PDMA, QDMA or a mix of the 2 + * @pdma_glo_cfg: the default DMA configuration + * @rx_int: the TX interrupt bits used by the SoC + * @tx_int: the TX interrupt bits used by the SoC + * @status_int: the Status interrupt bits used by the SoC + * @checksum_bit: the bits used to turn on HW checksumming + * @txd4: default value of the TXD4 descriptor + * @mac_count: the number of MACs that the SoC has + * @new_stats: there is a old and new way to read hardware stats + * registers + * @jumbo_frame: does the SoC support jumbo frames ? + * @rx_2b_offset: tell the rx dma to offset the data by 2 bytes + * @rx_sg_dma: scatter gather support + * @padding_64b enable 64 bit padding + * @padding_bug: rt2880 has a padding bug + * @has_switch: does the SoC have a built-in switch + * + * Although all of the supported SoCs share the same basic functionality, there + * are several SoC specific functions and features that we need to support. This + * struct holds the SoC specific data so that the common core can figure out + * how to setup and use these differences. + */ +struct mtk_soc_data { + const u16 *reg_table; + + void (*init_data)(struct mtk_soc_data *data, struct net_device *netdev); + void (*reset_fe)(struct mtk_eth *eth); + void (*set_mac)(struct mtk_mac *mac, unsigned char *macaddr); + int (*fwd_config)(struct mtk_eth *eth); + int (*switch_init)(struct mtk_eth *eth); + void (*port_init)(struct mtk_eth *eth, struct mtk_mac *mac, + struct device_node *port); + int (*has_carrier)(struct mtk_eth *eth); + int (*mdio_init)(struct mtk_eth *eth); + void (*mdio_cleanup)(struct mtk_eth *eth); + int (*mdio_write)(struct mii_bus *bus, int phy_addr, int phy_reg, + u16 val); + int (*mdio_read)(struct mii_bus *bus, int phy_addr, int phy_reg); + void (*mdio_adjust_link)(struct mtk_eth *eth, int port); + u32 piac_offset; + netdev_features_t hw_features; + u32 dma_ring_size; + u32 napi_weight; + u32 dma_type; + u32 pdma_glo_cfg; + u32 rx_int; + u32 tx_int; + u32 status_int; + u32 checksum_bit; + u32 txd4; + u32 mac_count; + + u32 new_stats:1; + u32 jumbo_frame:1; + u32 rx_2b_offset:1; + u32 rx_sg_dma:1; + u32 padding_64b:1; + u32 padding_bug:1; + u32 has_switch:1; +}; + +/* ugly macro hack to make sure hw_stats and ethtool strings are consistent */ +#define MTK_STAT_OFFSET 0x40 +#define MTK_STAT_REG_DECLARE \ + _FE(tx_bytes) \ + _FE(tx_packets) \ + _FE(tx_skip) \ + _FE(tx_collisions) \ + _FE(rx_bytes) \ + _FE(rx_packets) \ + _FE(rx_overflow) \ + _FE(rx_fcs_errors) \ + _FE(rx_short_errors) \ + _FE(rx_long_errors) \ + _FE(rx_checksum_errors) \ + _FE(rx_flow_control_packets) + +/* struct mtk_hw_stats - the structure that holds the traffic statistics. + * @stats_lock: make sure that stats operations are atomic + * @reg_offset: the status register offset of the SoC + * @syncp: the refcount + * + * All of the supported SoCs have hardware counters for traffic statstics. + * Whenever the status IRQ triggers we can read the latest stats from these + * counters and store them in this struct. + */ +struct mtk_hw_stats { + spinlock_t stats_lock; + u32 reg_offset; + struct u64_stats_sync syncp; + +#define _FE(x) u64 x; + MTK_STAT_REG_DECLARE +#undef _FE +}; + +/* PDMA descriptor can point at 1-2 segments. This enum allows us to track how + * memory was allocated so that it can be freed properly + */ +enum mtk_tx_flags { + MTK_TX_FLAGS_SINGLE0 = 0x01, + MTK_TX_FLAGS_PAGE0 = 0x02, + MTK_TX_FLAGS_PAGE1 = 0x04, +}; + +/* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at + * by the TX descriptor s + * @skb: The SKB pointer of the packet being sent + * @dma_addr0: The base addr of the first segment + * @dma_len0: The length of the first segment + * @dma_addr1: The base addr of the second segment + * @dma_len1: The length of the second segment + */ +struct mtk_tx_buf { + struct sk_buff *skb; + u32 flags; + DEFINE_DMA_UNMAP_ADDR(dma_addr0); + DEFINE_DMA_UNMAP_LEN(dma_len0); + DEFINE_DMA_UNMAP_ADDR(dma_addr1); + DEFINE_DMA_UNMAP_LEN(dma_len1); +}; + +/* struct mtk_tx_ring - This struct holds info describing a TX ring + * @tx_dma: The descriptor ring + * @tx_buf: The memory pointed at by the ring + * @tx_phys: The physical addr of tx_buf + * @tx_next_free: Pointer to the next free descriptor + * @tx_last_free: Pointer to the last free descriptor + * @tx_thresh: The threshold of minimum amount of free descriptors + * @tx_map: Callback to map a new packet into the ring + * @tx_poll: Callback for the housekeeping function + * @tx_clean: Callback for the cleanup function + * @tx_ring_size: How many descriptors are in the ring + * @tx_free_idx: The index of th next free descriptor + * @tx_next_idx: QDMA uses a linked list. This element points to the next + * free descriptor in the list + * @tx_free_count: QDMA uses a linked list. Track how many free descriptors + * are present + */ +struct mtk_tx_ring { + struct mtk_tx_dma *tx_dma; + struct mtk_tx_buf *tx_buf; + dma_addr_t tx_phys; + struct mtk_tx_dma *tx_next_free; + struct mtk_tx_dma *tx_last_free; + u16 tx_thresh; + int (*tx_map)(struct sk_buff *skb, struct net_device *dev, int tx_num, + struct mtk_tx_ring *ring, bool gso); + int (*tx_poll)(struct mtk_eth *eth, int budget, bool *tx_again); + void (*tx_clean)(struct mtk_eth *eth); + + /* PDMA only */ + u16 tx_ring_size; + u16 tx_free_idx; + + /* QDMA only */ + u16 tx_next_idx; + atomic_t tx_free_count; +}; + +/* struct mtk_rx_ring - This struct holds info describing a RX ring + * @rx_dma: The descriptor ring + * @rx_data: The memory pointed at by the ring + * @trx_phys: The physical addr of rx_buf + * @rx_ring_size: How many descriptors are in the ring + * @rx_buf_size: The size of each packet buffer + * @rx_calc_idx: The current head of ring + */ +struct mtk_rx_ring { + struct mtk_rx_dma *rx_dma; + u8 **rx_data; + dma_addr_t rx_phys; + u16 rx_ring_size; + u16 frag_size; + u16 rx_buf_size; + u16 rx_calc_idx; +}; + +/* currently no SoC has more than 2 macs */ +#define MTK_MAX_DEVS 2 + +/* struct mtk_eth - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer + * @base: The mapped register i/o base + * @page_lock: Make sure that register operations are atomic + * @soc: pointer to our SoC specific data + * @dummy_dev: we run 2 netdevs on 1 physical DMA ring and need a + * dummy for NAPI to work + * @netdev: The netdev instances + * @mac: Each netdev is linked to a physical MAC + * @switch_np: The phandle for the switch + * @irq: The IRQ that we are using + * @msg_enable: Ethtool msg level + * @ysclk: The sysclk rate - neeed for calibration + * @ethsys: The register map pointing at the range used to setup + * MII modes + * @dma_refcnt: track how many netdevs are using the DMA engine + * @tx_ring: Pointer to the memore holding info about the TX ring + * @rx_ring: Pointer to the memore holding info about the RX ring + * @rx_napi: The NAPI struct + * @scratch_ring: Newer SoCs need memory for a second HW managed TX ring + * @scratch_head: The scratch memory that scratch_ring points to. + * @phy: Info about the attached PHYs + * @mii_bus: If there is a bus we need to create an instance for it + * @link: Track if the ports have a physical link + * @sw_priv: Pointer to the switches private data + * @vlan_map: RX VID tracking + */ + +struct mtk_eth { + struct device *dev; + void __iomem *base; + spinlock_t page_lock; + struct mtk_soc_data *soc; + struct net_device dummy_dev; + struct net_device *netdev[MTK_MAX_DEVS]; + struct mtk_mac *mac[MTK_MAX_DEVS]; + struct device_node *switch_np; + int irq; + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; + atomic_t dma_refcnt; + struct mtk_tx_ring tx_ring; + struct mtk_rx_ring rx_ring[2]; + struct napi_struct rx_napi; + struct mtk_tx_dma *scratch_ring; + void *scratch_head; + struct mtk_phy *phy; + struct mii_bus *mii_bus; + int link[8]; + void *sw_priv; + unsigned long vlan_map; +}; + +/* struct mtk_mac - the structure that holds the info about the MACs of the + * SoC + * @id: The number of the MAC + * @of_node: Our devicetree node + * @hw: Backpointer to our main datastruture + * @hw_stats: Packet statistics counter + * @phy_dev: The attached PHY if available + * @phy_flags: The PHYs flags + * @pending_work: The workqueue used to reset the dma ring + */ +struct mtk_mac { + int id; + struct device_node *of_node; + struct mtk_eth *hw; + struct mtk_hw_stats *hw_stats; + struct phy_device *phy_dev; + u32 phy_flags; + struct work_struct pending_work; +}; + +/* the struct describing the SoC. these are declared in the soc_xyz.c files */ +extern const struct of_device_id of_mtk_match[]; + +/* read the hardware status register */ +void mtk_stats_update_mac(struct mtk_mac *mac); + +/* default checksum setup handler */ +void mtk_reset(struct mtk_eth *eth, u32 reset_bits); + +/* register i/o wrappers */ +void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); +u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + +/* default clock calibration handler */ +int mtk_set_clock_cycle(struct mtk_eth *eth); + +/* default checksum setup handler */ +void mtk_csum_config(struct mtk_eth *eth); + +/* default forward config handler */ +void mtk_fwd_config(struct mtk_eth *eth); + +#endif /* MTK_ETH_H */ diff --git a/drivers/staging/mt7621-eth/soc_mt7621.c b/drivers/staging/mt7621-eth/soc_mt7621.c new file mode 100644 index 000000000000..743c0eed89b6 --- /dev/null +++ b/drivers/staging/mt7621-eth/soc_mt7621.c @@ -0,0 +1,160 @@ +/* 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; version 2 of the License + * + * 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. + * + * Copyright (C) 2009-2016 John Crispin <blogic@openwrt.org> + * Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com> + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/if_vlan.h> +#include <linux/of_net.h> + +#include <asm/mach-ralink/ralink_regs.h> + +#include "mtk_eth_soc.h" +#include "gsw_mt7620.h" +#include "mdio.h" + +#define MT7620_CDMA_CSG_CFG 0x400 +#define MT7621_CDMP_IG_CTRL (MT7620_CDMA_CSG_CFG + 0x00) +#define MT7621_CDMP_EG_CTRL (MT7620_CDMA_CSG_CFG + 0x04) +#define MT7621_RESET_FE BIT(6) +#define MT7621_L4_VALID BIT(24) + +#define MT7621_TX_DMA_UDF BIT(19) + +#define CDMA_ICS_EN BIT(2) +#define CDMA_UCS_EN BIT(1) +#define CDMA_TCS_EN BIT(0) + +#define GDMA_ICS_EN BIT(22) +#define GDMA_TCS_EN BIT(21) +#define GDMA_UCS_EN BIT(20) + +/* frame engine counters */ +#define MT7621_REG_MIB_OFFSET 0x2000 +#define MT7621_PPE_AC_BCNT0 (MT7621_REG_MIB_OFFSET + 0x00) +#define MT7621_GDM1_TX_GBCNT (MT7621_REG_MIB_OFFSET + 0x400) +#define MT7621_GDM2_TX_GBCNT (MT7621_GDM1_TX_GBCNT + 0x40) + +#define GSW_REG_GDMA1_MAC_ADRL 0x508 +#define GSW_REG_GDMA1_MAC_ADRH 0x50C +#define GSW_REG_GDMA2_MAC_ADRL 0x1508 +#define GSW_REG_GDMA2_MAC_ADRH 0x150C + + +#define MT7621_MTK_RST_GL 0x04 +#define MT7620_MTK_INT_STATUS2 0x08 + +/* MTK_INT_STATUS reg on mt7620 define CNT_GDM1_AF at BIT(29) + * but after test it should be BIT(13). + */ +#define MT7621_MTK_GDM1_AF BIT(28) +#define MT7621_MTK_GDM2_AF BIT(29) + +static const u16 mt7621_reg_table[MTK_REG_COUNT] = { + [MTK_REG_PDMA_GLO_CFG] = RT5350_PDMA_GLO_CFG, + [MTK_REG_PDMA_RST_CFG] = RT5350_PDMA_RST_CFG, + [MTK_REG_DLY_INT_CFG] = RT5350_DLY_INT_CFG, + [MTK_REG_TX_BASE_PTR0] = RT5350_TX_BASE_PTR0, + [MTK_REG_TX_MAX_CNT0] = RT5350_TX_MAX_CNT0, + [MTK_REG_TX_CTX_IDX0] = RT5350_TX_CTX_IDX0, + [MTK_REG_TX_DTX_IDX0] = RT5350_TX_DTX_IDX0, + [MTK_REG_RX_BASE_PTR0] = RT5350_RX_BASE_PTR0, + [MTK_REG_RX_MAX_CNT0] = RT5350_RX_MAX_CNT0, + [MTK_REG_RX_CALC_IDX0] = RT5350_RX_CALC_IDX0, + [MTK_REG_RX_DRX_IDX0] = RT5350_RX_DRX_IDX0, + [MTK_REG_MTK_INT_ENABLE] = RT5350_MTK_INT_ENABLE, + [MTK_REG_MTK_INT_STATUS] = RT5350_MTK_INT_STATUS, + [MTK_REG_MTK_DMA_VID_BASE] = 0, + [MTK_REG_MTK_COUNTER_BASE] = MT7621_GDM1_TX_GBCNT, + [MTK_REG_MTK_RST_GL] = MT7621_MTK_RST_GL, + [MTK_REG_MTK_INT_STATUS2] = MT7620_MTK_INT_STATUS2, +}; + +static void mt7621_mtk_reset(struct mtk_eth *eth) +{ + mtk_reset(eth, MT7621_RESET_FE); +} + +static int mt7621_fwd_config(struct mtk_eth *eth) +{ + /* Setup GMAC1 only, there is no support for GMAC2 yet */ + mtk_w32(eth, mtk_r32(eth, MT7620_GDMA1_FWD_CFG) & ~0xffff, + MT7620_GDMA1_FWD_CFG); + + /* Enable RX checksum */ + mtk_w32(eth, mtk_r32(eth, MT7620_GDMA1_FWD_CFG) | (GDMA_ICS_EN | + GDMA_TCS_EN | GDMA_UCS_EN), + MT7620_GDMA1_FWD_CFG); + + /* Enable RX VLan Offloading */ + mtk_w32(eth, 0, MT7621_CDMP_EG_CTRL); + + return 0; +} + +static void mt7621_set_mac(struct mtk_mac *mac, unsigned char *hwaddr) +{ + unsigned long flags; + + spin_lock_irqsave(&mac->hw->page_lock, flags); + if (mac->id == 0) { + mtk_w32(mac->hw, (hwaddr[0] << 8) | hwaddr[1], GSW_REG_GDMA1_MAC_ADRH); + mtk_w32(mac->hw, (hwaddr[2] << 24) | (hwaddr[3] << 16) | + (hwaddr[4] << 8) | hwaddr[5], + GSW_REG_GDMA1_MAC_ADRL); + } + if (mac->id == 1) { + mtk_w32(mac->hw, (hwaddr[0] << 8) | hwaddr[1], GSW_REG_GDMA2_MAC_ADRH); + mtk_w32(mac->hw, (hwaddr[2] << 24) | (hwaddr[3] << 16) | + (hwaddr[4] << 8) | hwaddr[5], + GSW_REG_GDMA2_MAC_ADRL); + } + spin_unlock_irqrestore(&mac->hw->page_lock, flags); +} + +static struct mtk_soc_data mt7621_data = { + .hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_IPV6_CSUM, + .dma_type = MTK_PDMA, + .dma_ring_size = 256, + .napi_weight = 64, + .new_stats = 1, + .padding_64b = 1, + .rx_2b_offset = 1, + .rx_sg_dma = 1, + .has_switch = 1, + .mac_count = 2, + .reset_fe = mt7621_mtk_reset, + .set_mac = mt7621_set_mac, + .fwd_config = mt7621_fwd_config, + .switch_init = mtk_gsw_init, + .reg_table = mt7621_reg_table, + .pdma_glo_cfg = MTK_PDMA_SIZE_16DWORDS, + .rx_int = RT5350_RX_DONE_INT, + .tx_int = RT5350_TX_DONE_INT, + .status_int = MT7621_MTK_GDM1_AF | MT7621_MTK_GDM2_AF, + .checksum_bit = MT7621_L4_VALID, + .has_carrier = mt7620_has_carrier, + .mdio_read = mt7620_mdio_read, + .mdio_write = mt7620_mdio_write, + .mdio_adjust_link = mt7620_mdio_link_adjust, +}; + +const struct of_device_id of_mtk_match[] = { + { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_mtk_match); diff --git a/drivers/staging/mt7621-gpio/Kconfig b/drivers/staging/mt7621-gpio/Kconfig new file mode 100644 index 000000000000..c741ec3f4e50 --- /dev/null +++ b/drivers/staging/mt7621-gpio/Kconfig @@ -0,0 +1,6 @@ +config GPIO_MT7621 + bool "Mediatek GPIO Support" + depends on SOC_MT7620 || SOC_MT7621 + select ARCH_REQUIRE_GPIOLIB + help + Say yes here to support the Mediatek SoC GPIO device diff --git a/drivers/staging/mt7621-gpio/Makefile b/drivers/staging/mt7621-gpio/Makefile new file mode 100644 index 000000000000..e269ab1b8717 --- /dev/null +++ b/drivers/staging/mt7621-gpio/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o + +ccflags-y += -I$(srctree)/$(src)/include diff --git a/drivers/staging/mt7621-gpio/TODO b/drivers/staging/mt7621-gpio/TODO new file mode 100644 index 000000000000..71439054e2e4 --- /dev/null +++ b/drivers/staging/mt7621-gpio/TODO @@ -0,0 +1,5 @@ + +- general code review and clean up +- ensure device-tree requirements are documented + +Cc: NeilBrown <neil@brown.name> diff --git a/drivers/staging/mt7621-gpio/gpio-mt7621.c b/drivers/staging/mt7621-gpio/gpio-mt7621.c new file mode 100644 index 000000000000..51235687ddb6 --- /dev/null +++ b/drivers/staging/mt7621-gpio/gpio-mt7621.c @@ -0,0 +1,352 @@ +/* + * 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. + * + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/io.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/spinlock.h> +#include <linux/irqdomain.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#define MTK_MAX_BANK 3 +#define MTK_BANK_WIDTH 32 + +enum mediatek_gpio_reg { + GPIO_REG_CTRL = 0, + GPIO_REG_POL, + GPIO_REG_DATA, + GPIO_REG_DSET, + GPIO_REG_DCLR, + GPIO_REG_REDGE, + GPIO_REG_FEDGE, + GPIO_REG_HLVL, + GPIO_REG_LLVL, + GPIO_REG_STAT, + GPIO_REG_EDGE, +}; + +static void __iomem *mediatek_gpio_membase; +static int mediatek_gpio_irq; +static struct irq_domain *mediatek_gpio_irq_domain; + +static struct mtk_gc { + struct gpio_chip chip; + spinlock_t lock; + int bank; + u32 rising; + u32 falling; +} *gc_map[MTK_MAX_BANK]; + +static inline struct mtk_gc +*to_mediatek_gpio(struct gpio_chip *chip) +{ + struct mtk_gc *mgc; + + mgc = container_of(chip, struct mtk_gc, chip); + + return mgc; +} + +static inline void +mtk_gpio_w32(struct mtk_gc *rg, u8 reg, u32 val) +{ + iowrite32(val, mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); +} + +static inline u32 +mtk_gpio_r32(struct mtk_gc *rg, u8 reg) +{ + return ioread32(mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); +} + +static void +mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct mtk_gc *rg = to_mediatek_gpio(chip); + + mtk_gpio_w32(rg, (value) ? GPIO_REG_DSET : GPIO_REG_DCLR, BIT(offset)); +} + +static int +mediatek_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct mtk_gc *rg = to_mediatek_gpio(chip); + + return !!(mtk_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset)); +} + +static int +mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct mtk_gc *rg = to_mediatek_gpio(chip); + unsigned long flags; + u32 t; + + spin_lock_irqsave(&rg->lock, flags); + t = mtk_gpio_r32(rg, GPIO_REG_CTRL); + t &= ~BIT(offset); + mtk_gpio_w32(rg, GPIO_REG_CTRL, t); + spin_unlock_irqrestore(&rg->lock, flags); + + return 0; +} + +static int +mediatek_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct mtk_gc *rg = to_mediatek_gpio(chip); + unsigned long flags; + u32 t; + + spin_lock_irqsave(&rg->lock, flags); + t = mtk_gpio_r32(rg, GPIO_REG_CTRL); + t |= BIT(offset); + mtk_gpio_w32(rg, GPIO_REG_CTRL, t); + mediatek_gpio_set(chip, offset, value); + spin_unlock_irqrestore(&rg->lock, flags); + + return 0; +} + +static int +mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +{ + struct mtk_gc *rg = to_mediatek_gpio(chip); + unsigned long flags; + u32 t; + + spin_lock_irqsave(&rg->lock, flags); + t = mtk_gpio_r32(rg, GPIO_REG_CTRL); + spin_unlock_irqrestore(&rg->lock, flags); + + if (t & BIT(offset)) + return 0; + + return 1; +} + +static int +mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned pin) +{ + struct mtk_gc *rg = to_mediatek_gpio(chip); + + return irq_create_mapping(mediatek_gpio_irq_domain, pin + (rg->bank * MTK_BANK_WIDTH)); +} + +static int +mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank) +{ + const __be32 *id = of_get_property(bank, "reg", NULL); + struct mtk_gc *rg = devm_kzalloc(&pdev->dev, + sizeof(struct mtk_gc), GFP_KERNEL); + + if (!rg || !id || be32_to_cpu(*id) > MTK_MAX_BANK) + return -ENOMEM; + + gc_map[be32_to_cpu(*id)] = rg; + + memset(rg, 0, sizeof(struct mtk_gc)); + + spin_lock_init(&rg->lock); + + rg->chip.parent = &pdev->dev; + rg->chip.label = dev_name(&pdev->dev); + rg->chip.of_node = bank; + rg->chip.base = MTK_BANK_WIDTH * be32_to_cpu(*id); + rg->chip.ngpio = MTK_BANK_WIDTH; + rg->chip.direction_input = mediatek_gpio_direction_input; + rg->chip.direction_output = mediatek_gpio_direction_output; + rg->chip.get_direction = mediatek_gpio_get_direction; + rg->chip.get = mediatek_gpio_get; + rg->chip.set = mediatek_gpio_set; + if (mediatek_gpio_irq_domain) + rg->chip.to_irq = mediatek_gpio_to_irq; + rg->bank = be32_to_cpu(*id); + + /* set polarity to low for all gpios */ + mtk_gpio_w32(rg, GPIO_REG_POL, 0); + + dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); + + return gpiochip_add(&rg->chip); +} + +static void +mediatek_gpio_irq_handler(struct irq_desc *desc) +{ + int i; + + for (i = 0; i < MTK_MAX_BANK; i++) { + struct mtk_gc *rg = gc_map[i]; + unsigned long pending; + int bit; + + if (!rg) + continue; + + pending = mtk_gpio_r32(rg, GPIO_REG_STAT); + + for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { + u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit); + + generic_handle_irq(map); + mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); + } + } +} + +static void +mediatek_gpio_irq_unmask(struct irq_data *d) +{ + int pin = d->hwirq; + int bank = pin / 32; + struct mtk_gc *rg = gc_map[bank]; + unsigned long flags; + u32 rise, fall; + + if (!rg) + return; + + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + + spin_lock_irqsave(&rg->lock, flags); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(d->hwirq) & rg->rising)); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(d->hwirq) & rg->falling)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static void +mediatek_gpio_irq_mask(struct irq_data *d) +{ + int pin = d->hwirq; + int bank = pin / 32; + struct mtk_gc *rg = gc_map[bank]; + unsigned long flags; + u32 rise, fall; + + if (!rg) + return; + + rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); + fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); + + spin_lock_irqsave(&rg->lock, flags); + mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(d->hwirq)); + mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(d->hwirq)); + spin_unlock_irqrestore(&rg->lock, flags); +} + +static int +mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) +{ + int pin = d->hwirq; + int bank = pin / 32; + struct mtk_gc *rg = gc_map[bank]; + u32 mask = BIT(d->hwirq); + + if (!rg) + return -1; + + if (type == IRQ_TYPE_PROBE) { + if ((rg->rising | rg->falling) & mask) + return 0; + + type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + } + + if (type & IRQ_TYPE_EDGE_RISING) + rg->rising |= mask; + else + rg->rising &= ~mask; + + if (type & IRQ_TYPE_EDGE_FALLING) + rg->falling |= mask; + else + rg->falling &= ~mask; + + return 0; +} + +static struct irq_chip mediatek_gpio_irq_chip = { + .name = "GPIO", + .irq_unmask = mediatek_gpio_irq_unmask, + .irq_mask = mediatek_gpio_irq_mask, + .irq_mask_ack = mediatek_gpio_irq_mask, + .irq_set_type = mediatek_gpio_irq_type, +}; + +static int +mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, handle_level_irq); + irq_set_handler_data(irq, d); + + return 0; +} + +static const struct irq_domain_ops irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = mediatek_gpio_gpio_map, +}; + +static int +mediatek_gpio_probe(struct platform_device *pdev) +{ + struct device_node *bank, *np = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mediatek_gpio_membase)) + return PTR_ERR(mediatek_gpio_membase); + + mediatek_gpio_irq = irq_of_parse_and_map(np, 0); + if (mediatek_gpio_irq) { + mediatek_gpio_irq_domain = irq_domain_add_linear(np, + MTK_MAX_BANK * MTK_BANK_WIDTH, + &irq_domain_ops, NULL); + if (!mediatek_gpio_irq_domain) + dev_err(&pdev->dev, "irq_domain_add_linear failed\n"); + } + + for_each_child_of_node(np, bank) + if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank")) + mediatek_gpio_bank_probe(pdev, bank); + + if (mediatek_gpio_irq_domain) + irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler); + + return 0; +} + +static const struct of_device_id mediatek_gpio_match[] = { + { .compatible = "mtk,mt7621-gpio" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mediatek_gpio_match); + +static struct platform_driver mediatek_gpio_driver = { + .probe = mediatek_gpio_probe, + .driver = { + .name = "mt7621_gpio", + .of_match_table = mediatek_gpio_match, + }, +}; + +static int __init +mediatek_gpio_init(void) +{ + return platform_driver_register(&mediatek_gpio_driver); +} + +subsys_initcall(mediatek_gpio_init); diff --git a/drivers/staging/mt7621-mmc/Kconfig b/drivers/staging/mt7621-mmc/Kconfig new file mode 100644 index 000000000000..c6dfe8c637dc --- /dev/null +++ b/drivers/staging/mt7621-mmc/Kconfig @@ -0,0 +1,16 @@ +config MTK_MMC + tristate "MTK SD/MMC" + depends on !MTD_NAND_RALINK && MMC + +config MTK_AEE_KDUMP + bool "MTK AEE KDUMP" + depends on MTK_MMC + +config MTK_MMC_CD_POLL + bool "Card Detect with Polling" + depends on MTK_MMC + +config MTK_MMC_EMMC_8BIT + bool "eMMC 8-bit support" + depends on MTK_MMC && RALINK_MT7628 + diff --git a/drivers/staging/mt7621-mmc/Makefile b/drivers/staging/mt7621-mmc/Makefile new file mode 100644 index 000000000000..caead0b54703 --- /dev/null +++ b/drivers/staging/mt7621-mmc/Makefile @@ -0,0 +1,42 @@ +# Copyright Statement: +# +# This software/firmware and related documentation ("MediaTek Software") are +# protected under relevant copyright laws. The information contained herein +# is confidential and proprietary to MediaTek Inc. and/or its licensors. +# Without the prior written permission of MediaTek inc. and/or its licensors, +# any reproduction, modification, use or disclosure of MediaTek Software, +# and information contained herein, in whole or in part, shall be strictly prohibited. +# +# MediaTek Inc. (C) 2010. All rights reserved. +# +# BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES +# THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") +# RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON +# AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. +# NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE +# SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR +# SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH +# THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES +# THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES +# CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK +# SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR +# STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND +# CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, +# AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, +# OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO +# MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. +# +# The following software/firmware and/or related documentation ("MediaTek Software") +# have been modified by MediaTek Inc. All revisions are subject to any receiver's +# applicable license agreements with MediaTek Inc. + +obj-$(CONFIG_MTK_MMC) += mtk_sd.o +mtk_sd-objs := sd.o dbg.o +ifeq ($(CONFIG_MTK_AEE_KDUMP),y) +EXTRA_CFLAGS += -DMT6575_SD_DEBUG +endif + +clean: + @rm -f *.o modules.order .*.cmd diff --git a/drivers/staging/mt7621-mmc/TODO b/drivers/staging/mt7621-mmc/TODO new file mode 100644 index 000000000000..febb32d37e07 --- /dev/null +++ b/drivers/staging/mt7621-mmc/TODO @@ -0,0 +1,8 @@ + +- general code review and clean up +- ensure device-tree requirements are documented +- should probably be merged with drivers/mmc/host/mtk-sd.c +- possibly fix to work with highmem pages so a bounce buffer isn't + needed. + +Cc: NeilBrown <neil@brown.name> diff --git a/drivers/staging/mt7621-mmc/board.h b/drivers/staging/mt7621-mmc/board.h new file mode 100644 index 000000000000..33bfc7b9597a --- /dev/null +++ b/drivers/staging/mt7621-mmc/board.h @@ -0,0 +1,137 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#ifndef __ARCH_ARM_MACH_BOARD_H +#define __ARCH_ARM_MACH_BOARD_H + +#include <generated/autoconf.h> +#include <linux/pm.h> +/* --- chhung */ +// #include <mach/mt6575.h> +// #include <board-custom.h> +/* end of chhung */ + +typedef void (*sdio_irq_handler_t)(void*); /* external irq handler */ +typedef void (*pm_callback_t)(pm_message_t state, void *data); + +#define MSDC_CD_PIN_EN (1 << 0) /* card detection pin is wired */ +#define MSDC_WP_PIN_EN (1 << 1) /* write protection pin is wired */ +#define MSDC_RST_PIN_EN (1 << 2) /* emmc reset pin is wired */ +#define MSDC_SDIO_IRQ (1 << 3) /* use internal sdio irq (bus) */ +#define MSDC_EXT_SDIO_IRQ (1 << 4) /* use external sdio irq */ +#define MSDC_REMOVABLE (1 << 5) /* removable slot */ +#define MSDC_SYS_SUSPEND (1 << 6) /* suspended by system */ +#define MSDC_HIGHSPEED (1 << 7) /* high-speed mode support */ +#define MSDC_UHS1 (1 << 8) /* uhs-1 mode support */ +#define MSDC_DDR (1 << 9) /* ddr mode support */ + + +#define MSDC_SMPL_RISING (0) +#define MSDC_SMPL_FALLING (1) + +#define MSDC_CMD_PIN (0) +#define MSDC_DAT_PIN (1) +#define MSDC_CD_PIN (2) +#define MSDC_WP_PIN (3) +#define MSDC_RST_PIN (4) + +enum { + MSDC_CLKSRC_48MHZ = 0, +// MSDC_CLKSRC_26MHZ = 0, +// MSDC_CLKSRC_197MHZ = 1, +// MSDC_CLKSRC_208MHZ = 2 +}; + +struct msdc_hw { + unsigned char clk_src; /* host clock source */ + unsigned char cmd_edge; /* command latch edge */ + unsigned char data_edge; /* data latch edge */ + unsigned char clk_drv; /* clock pad driving */ + unsigned char cmd_drv; /* command pad driving */ + unsigned char dat_drv; /* data pad driving */ + unsigned long flags; /* hardware capability flags */ + unsigned long data_pins; /* data pins */ + unsigned long data_offset; /* data address offset */ + + /* config gpio pull mode */ + void (*config_gpio_pin)(int type, int pull); + + /* external power control for card */ + void (*ext_power_on)(void); + void (*ext_power_off)(void); + + /* external sdio irq operations */ + void (*request_sdio_eirq)(sdio_irq_handler_t sdio_irq_handler, void *data); + void (*enable_sdio_eirq)(void); + void (*disable_sdio_eirq)(void); + + /* external cd irq operations */ + void (*request_cd_eirq)(sdio_irq_handler_t cd_irq_handler, void *data); + void (*enable_cd_eirq)(void); + void (*disable_cd_eirq)(void); + int (*get_cd_status)(void); + + /* power management callback for external module */ + void (*register_pm)(pm_callback_t pm_cb, void *data); +}; + +extern struct msdc_hw msdc0_hw; +extern struct msdc_hw msdc1_hw; +extern struct msdc_hw msdc2_hw; +extern struct msdc_hw msdc3_hw; + +/*GPS driver*/ +#define GPS_FLAG_FORCE_OFF 0x0001 +struct mt3326_gps_hardware { + int (*ext_power_on)(int); + int (*ext_power_off)(int); +}; +extern struct mt3326_gps_hardware mt3326_gps_hw; + +/* NAND driver */ +struct mt6575_nand_host_hw { + unsigned int nfi_bus_width; /* NFI_BUS_WIDTH */ + unsigned int nfi_access_timing; /* NFI_ACCESS_TIMING */ + unsigned int nfi_cs_num; /* NFI_CS_NUM */ + unsigned int nand_sec_size; /* NAND_SECTOR_SIZE */ + unsigned int nand_sec_shift; /* NAND_SECTOR_SHIFT */ + unsigned int nand_ecc_size; + unsigned int nand_ecc_bytes; + unsigned int nand_ecc_mode; +}; +extern struct mt6575_nand_host_hw mt6575_nand_hw; + +#endif /* __ARCH_ARM_MACH_BOARD_H */ + diff --git a/drivers/staging/mt7621-mmc/dbg.c b/drivers/staging/mt7621-mmc/dbg.c new file mode 100644 index 000000000000..4dc115b53993 --- /dev/null +++ b/drivers/staging/mt7621-mmc/dbg.c @@ -0,0 +1,347 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/kthread.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/string.h> +#include <linux/uaccess.h> +// #include <mach/mt6575_gpt.h> /* --- by chhung */ +#include "dbg.h" +#include "mt6575_sd.h" +#include <linux/seq_file.h> + +static char cmd_buf[256]; + +/* for debug zone */ +unsigned int sd_debug_zone[4]={ + 0, + 0, + 0, + 0 +}; + +/* mode select */ +u32 dma_size[4]={ + 512, + 512, + 512, + 512 +}; +msdc_mode drv_mode[4]={ + MODE_SIZE_DEP, /* using DMA or not depend on the size */ + MODE_SIZE_DEP, + MODE_SIZE_DEP, + MODE_SIZE_DEP +}; + +#if defined (MT6575_SD_DEBUG) +/* for driver profile */ +#define TICKS_ONE_MS (13000) +u32 gpt_enable = 0; +u32 sdio_pro_enable = 0; /* make sure gpt is enabled */ +u32 sdio_pro_time = 0; /* no more than 30s */ +struct sdio_profile sdio_perfomance = {0}; + +#if 0 /* --- chhung */ +void msdc_init_gpt(void) +{ + GPT_CONFIG config; + + config.num = GPT6; + config.mode = GPT_FREE_RUN; + config.clkSrc = GPT_CLK_SRC_SYS; + config.clkDiv = GPT_CLK_DIV_1; /* 13MHz GPT6 */ + + if (GPT_Config(config) == FALSE ) + return; + + GPT_Start(GPT6); +} +#endif /* end of --- */ + +u32 msdc_time_calc(u32 old_L32, u32 old_H32, u32 new_L32, u32 new_H32) +{ + u32 ret = 0; + + if (new_H32 == old_H32) { + ret = new_L32 - old_L32; + } else if(new_H32 == (old_H32 + 1)) { + if (new_L32 > old_L32) { + printk("msdc old_L<0x%x> new_L<0x%x>\n", old_L32, new_L32); + } + ret = (0xffffffff - old_L32); + ret += new_L32; + } else { + printk("msdc old_H<0x%x> new_H<0x%x>\n", old_H32, new_H32); + } + + return ret; +} + +void msdc_sdio_profile(struct sdio_profile* result) +{ + struct cmd_profile* cmd; + u32 i; + + printk("sdio === performance dump ===\n"); + printk("sdio === total execute tick<%d> time<%dms> Tx<%dB> Rx<%dB>\n", + result->total_tc, result->total_tc / TICKS_ONE_MS, + result->total_tx_bytes, result->total_rx_bytes); + + /* CMD52 Dump */ + cmd = &result->cmd52_rx; + printk("sdio === CMD52 Rx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n", cmd->count, cmd->tot_tc, + cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count); + cmd = &result->cmd52_tx; + printk("sdio === CMD52 Tx <%d>times tick<%d> Max<%d> Min<%d> Aver<%d>\n", cmd->count, cmd->tot_tc, + cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count); + + /* CMD53 Rx bytes + block mode */ + for (i=0; i<512; i++) { + cmd = &result->cmd53_rx_byte[i]; + if (cmd->count) { + printk("sdio<%6d><%3dB>_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc, + cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count, + cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10)); + } + } + for (i=0; i<100; i++) { + cmd = &result->cmd53_rx_blk[i]; + if (cmd->count) { + printk("sdio<%6d><%3d>B_Rx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc, + cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count, + cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10)); + } + } + + /* CMD53 Tx bytes + block mode */ + for (i=0; i<512; i++) { + cmd = &result->cmd53_tx_byte[i]; + if (cmd->count) { + printk("sdio<%6d><%3dB>_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc, + cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count, + cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10)); + } + } + for (i=0; i<100; i++) { + cmd = &result->cmd53_tx_blk[i]; + if (cmd->count) { + printk("sdio<%6d><%3d>B_Tx_<%9d><%9d><%6d><%6d>_<%9dB><%2dM>\n", cmd->count, i, cmd->tot_tc, + cmd->max_tc, cmd->min_tc, cmd->tot_tc/cmd->count, + cmd->tot_bytes, (cmd->tot_bytes/10)*13 / (cmd->tot_tc/10)); + } + } + + printk("sdio === performance dump done ===\n"); +} + +//========= sdio command table =========== +void msdc_performance(u32 opcode, u32 sizes, u32 bRx, u32 ticks) +{ + struct sdio_profile* result = &sdio_perfomance; + struct cmd_profile* cmd; + u32 block; + + if (sdio_pro_enable == 0) { + return; + } + + if (opcode == 52) { + cmd = bRx ? &result->cmd52_rx : &result->cmd52_tx; + } else if (opcode == 53) { + if (sizes < 512) { + cmd = bRx ? &result->cmd53_rx_byte[sizes] : &result->cmd53_tx_byte[sizes]; + } else { + block = sizes / 512; + if (block >= 99) { + printk("cmd53 error blocks\n"); + while(1); + } + cmd = bRx ? &result->cmd53_rx_blk[block] : &result->cmd53_tx_blk[block]; + } + } else { + return; + } + + /* update the members */ + if (ticks > cmd->max_tc){ + cmd->max_tc = ticks; + } + if (cmd->min_tc == 0 || ticks < cmd->min_tc) { + cmd->min_tc = ticks; + } + cmd->tot_tc += ticks; + cmd->tot_bytes += sizes; + cmd->count ++; + + if (bRx) { + result->total_rx_bytes += sizes; + } else { + result->total_tx_bytes += sizes; + } + result->total_tc += ticks; + + /* dump when total_tc > 30s */ + if (result->total_tc >= sdio_pro_time * TICKS_ONE_MS * 1000) { + msdc_sdio_profile(result); + memset(result, 0 , sizeof(struct sdio_profile)); + } +} + +//========== driver proc interface =========== +static int msdc_debug_proc_read(struct seq_file *s, void *p) +{ + seq_printf(s, "\n=========================================\n"); + seq_printf(s, "Index<0> + Id + Zone\n"); + seq_printf(s, "-> PWR<9> WRN<8> | FIO<7> OPS<6> FUN<5> CFG<4> | INT<3> RSP<2> CMD<1> DMA<0>\n"); + seq_printf(s, "-> echo 0 3 0x3ff >msdc_bebug -> host[3] debug zone set to 0x3ff\n"); + seq_printf(s, "-> MSDC[0] Zone: 0x%.8x\n", sd_debug_zone[0]); + seq_printf(s, "-> MSDC[1] Zone: 0x%.8x\n", sd_debug_zone[1]); + seq_printf(s, "-> MSDC[2] Zone: 0x%.8x\n", sd_debug_zone[2]); + seq_printf(s, "-> MSDC[3] Zone: 0x%.8x\n", sd_debug_zone[3]); + + seq_printf(s, "Index<1> + ID:4|Mode:4 + DMA_SIZE\n"); + seq_printf(s, "-> 0)PIO 1)DMA 2)SIZE\n"); + seq_printf(s, "-> echo 1 22 0x200 >msdc_bebug -> host[2] size mode, dma when >= 512\n"); + seq_printf(s, "-> MSDC[0] mode<%d> size<%d>\n", drv_mode[0], dma_size[0]); + seq_printf(s, "-> MSDC[1] mode<%d> size<%d>\n", drv_mode[1], dma_size[1]); + seq_printf(s, "-> MSDC[2] mode<%d> size<%d>\n", drv_mode[2], dma_size[2]); + seq_printf(s, "-> MSDC[3] mode<%d> size<%d>\n", drv_mode[3], dma_size[3]); + + seq_printf(s, "Index<3> + SDIO_PROFILE + TIME\n"); + seq_printf(s, "-> echo 3 1 0x1E >msdc_bebug -> enable sdio_profile, 30s\n"); + seq_printf(s, "-> SDIO_PROFILE<%d> TIME<%ds>\n", sdio_pro_enable, sdio_pro_time); + seq_printf(s, "=========================================\n\n"); + + return 0; +} + +static ssize_t msdc_debug_proc_write(struct file *file, + const char __user *buf, size_t count, loff_t *data) +{ + int ret; + + int cmd, p1, p2; + int id, zone; + int mode, size; + + if (count == 0)return -1; + if(count > 255)count = 255; + + ret = copy_from_user(cmd_buf, buf, count); + if (ret < 0)return -1; + + cmd_buf[count] = '\0'; + printk("msdc Write %s\n", cmd_buf); + + sscanf(cmd_buf, "%x %x %x", &cmd, &p1, &p2); + + if(cmd == SD_TOOL_ZONE) { + id = p1; zone = p2; zone &= 0x3ff; + printk("msdc host_id<%d> zone<0x%.8x>\n", id, zone); + if(id >=0 && id<=3){ + sd_debug_zone[id] = zone; + } + else if(id == 4){ + sd_debug_zone[0] = sd_debug_zone[1] = zone; + sd_debug_zone[2] = sd_debug_zone[3] = zone; + } + else{ + printk("msdc host_id error when set debug zone\n"); + } + } else if (cmd == SD_TOOL_DMA_SIZE) { + id = p1>>4; mode = (p1&0xf); size = p2; + if(id >=0 && id<=3){ + drv_mode[id] = mode; + dma_size[id] = p2; + } + else if(id == 4){ + drv_mode[0] = drv_mode[1] = mode; + drv_mode[2] = drv_mode[3] = mode; + dma_size[0] = dma_size[1] = p2; + dma_size[2] = dma_size[3] = p2; + } + else{ + printk("msdc host_id error when select mode\n"); + } + } else if (cmd == SD_TOOL_SDIO_PROFILE) { + if (p1 == 1) { /* enable profile */ + if (gpt_enable == 0) { + // msdc_init_gpt(); /* --- by chhung */ + gpt_enable = 1; + } + sdio_pro_enable = 1; + if (p2 == 0) p2 = 1; if (p2 >= 30) p2 = 30; + sdio_pro_time = p2 ; + } else if (p1 == 0) { + /* todo */ + sdio_pro_enable = 0; + } + } + + return count; +} + +static int msdc_debug_show(struct inode *inode, struct file *file) +{ + return single_open(file, msdc_debug_proc_read, NULL); +} + +static const struct file_operations msdc_debug_fops = { + .owner = THIS_MODULE, + .open = msdc_debug_show, + .read = seq_read, + .write = msdc_debug_proc_write, + .llseek = seq_lseek, + .release = single_release, +}; + +int msdc_debug_proc_init(void) +{ + struct proc_dir_entry *de = proc_create("msdc_debug", 0667, NULL, &msdc_debug_fops); + + if (!de || IS_ERR(de)) + printk("!! Create MSDC debug PROC fail !!\n"); + + return 0 ; +} +EXPORT_SYMBOL_GPL(msdc_debug_proc_init); +#endif diff --git a/drivers/staging/mt7621-mmc/dbg.h b/drivers/staging/mt7621-mmc/dbg.h new file mode 100644 index 000000000000..e58c4312933e --- /dev/null +++ b/drivers/staging/mt7621-mmc/dbg.h @@ -0,0 +1,156 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ +#ifndef __MT_MSDC_DEUBG__ +#define __MT_MSDC_DEUBG__ + +//========================== +extern u32 sdio_pro_enable; +/* for a type command, e.g. CMD53, 2 blocks */ +struct cmd_profile { + u32 max_tc; /* Max tick count */ + u32 min_tc; + u32 tot_tc; /* total tick count */ + u32 tot_bytes; + u32 count; /* the counts of the command */ +}; + +/* dump when total_tc and total_bytes */ +struct sdio_profile { + u32 total_tc; /* total tick count of CMD52 and CMD53 */ + u32 total_tx_bytes; /* total bytes of CMD53 Tx */ + u32 total_rx_bytes; /* total bytes of CMD53 Rx */ + + /*CMD52*/ + struct cmd_profile cmd52_tx; + struct cmd_profile cmd52_rx; + + /*CMD53 in byte unit */ + struct cmd_profile cmd53_tx_byte[512]; + struct cmd_profile cmd53_rx_byte[512]; + + /*CMD53 in block unit */ + struct cmd_profile cmd53_tx_blk[100]; + struct cmd_profile cmd53_rx_blk[100]; +}; + +//========================== +typedef enum { + SD_TOOL_ZONE = 0, + SD_TOOL_DMA_SIZE = 1, + SD_TOOL_PM_ENABLE = 2, + SD_TOOL_SDIO_PROFILE = 3, +} msdc_dbg; + +typedef enum { + MODE_PIO = 0, + MODE_DMA = 1, + MODE_SIZE_DEP = 2, +} msdc_mode; +extern msdc_mode drv_mode[4]; +extern u32 dma_size[4]; + +/* Debug message event */ +#define DBG_EVT_NONE (0) /* No event */ +#define DBG_EVT_DMA (1 << 0) /* DMA related event */ +#define DBG_EVT_CMD (1 << 1) /* MSDC CMD related event */ +#define DBG_EVT_RSP (1 << 2) /* MSDC CMD RSP related event */ +#define DBG_EVT_INT (1 << 3) /* MSDC INT event */ +#define DBG_EVT_CFG (1 << 4) /* MSDC CFG event */ +#define DBG_EVT_FUC (1 << 5) /* Function event */ +#define DBG_EVT_OPS (1 << 6) /* Read/Write operation event */ +#define DBG_EVT_FIO (1 << 7) /* FIFO operation event */ +#define DBG_EVT_WRN (1 << 8) /* Warning event */ +#define DBG_EVT_PWR (1 << 9) /* Power event */ +#define DBG_EVT_ALL (0xffffffff) + +#define DBG_EVT_MASK (DBG_EVT_ALL) + +extern unsigned int sd_debug_zone[4]; +#define TAG "msdc" +#if 0 /* +++ chhung */ +#define BUG_ON(x) \ +do { \ + if (x) { \ + printk("[BUG] %s LINE:%d FILE:%s\n", #x, __LINE__, __FILE__); \ + while(1); \ + } \ +}while(0) +#endif /* end of +++ */ + +#define N_MSG(evt, fmt, args...) +/* +do { \ + if ((DBG_EVT_##evt) & sd_debug_zone[host->id]) { \ + printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \ + host->id, ##args , __FUNCTION__, __LINE__, current->comm, current->pid); \ + } \ +} while(0) +*/ + +#define ERR_MSG(fmt, args...) \ +do { \ + printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \ + host->id, ##args , __FUNCTION__, __LINE__, current->comm, current->pid); \ +} while(0); + +#if 1 +//defined CONFIG_MTK_MMC_CD_POLL +#define INIT_MSG(fmt, args...) +#define IRQ_MSG(fmt, args...) +#else +#define INIT_MSG(fmt, args...) \ +do { \ + printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d> PID<%s><0x%x>\n", \ + host->id, ##args , __FUNCTION__, __LINE__, current->comm, current->pid); \ +} while(0); + +/* PID in ISR in not corrent */ +#define IRQ_MSG(fmt, args...) \ +do { \ + printk(KERN_ERR TAG"%d -> "fmt" <- %s() : L<%d>\n", \ + host->id, ##args , __FUNCTION__, __LINE__); \ +} while(0); +#endif + +int msdc_debug_proc_init(void); + +#if 0 /* --- chhung */ +void msdc_init_gpt(void); +extern void GPT_GetCounter64(UINT32 *cntL32, UINT32 *cntH32); +#endif /* end of --- */ +u32 msdc_time_calc(u32 old_L32, u32 old_H32, u32 new_L32, u32 new_H32); +void msdc_performance(u32 opcode, u32 sizes, u32 bRx, u32 ticks); + +#endif diff --git a/drivers/staging/mt7621-mmc/mt6575_sd.h b/drivers/staging/mt7621-mmc/mt6575_sd.h new file mode 100644 index 000000000000..e90c4f1d1df7 --- /dev/null +++ b/drivers/staging/mt7621-mmc/mt6575_sd.h @@ -0,0 +1,1001 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + */ +/* MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#ifndef MT6575_SD_H +#define MT6575_SD_H + +#include <linux/bitops.h> +#include <linux/mmc/host.h> + +// #include <mach/mt6575_reg_base.h> /* --- by chhung */ + +/*--------------------------------------------------------------------------*/ +/* Common Macro */ +/*--------------------------------------------------------------------------*/ +#define REG_ADDR(x) ((volatile u32*)(base + OFFSET_##x)) + +/*--------------------------------------------------------------------------*/ +/* Common Definition */ +/*--------------------------------------------------------------------------*/ +#define MSDC_FIFO_SZ (128) +#define MSDC_FIFO_THD (64) // (128) +#define MSDC_NUM (4) + +#define MSDC_MS (0) +#define MSDC_SDMMC (1) + +#define MSDC_MODE_UNKNOWN (0) +#define MSDC_MODE_PIO (1) +#define MSDC_MODE_DMA_BASIC (2) +#define MSDC_MODE_DMA_DESC (3) +#define MSDC_MODE_DMA_ENHANCED (4) +#define MSDC_MODE_MMC_STREAM (5) + +#define MSDC_BUS_1BITS (0) +#define MSDC_BUS_4BITS (1) +#define MSDC_BUS_8BITS (2) + +#define MSDC_BRUST_8B (3) +#define MSDC_BRUST_16B (4) +#define MSDC_BRUST_32B (5) +#define MSDC_BRUST_64B (6) + +#define MSDC_PIN_PULL_NONE (0) +#define MSDC_PIN_PULL_DOWN (1) +#define MSDC_PIN_PULL_UP (2) +#define MSDC_PIN_KEEP (3) + +#define MSDC_MAX_SCLK (48000000) /* +/- by chhung */ +#define MSDC_MIN_SCLK (260000) + +#define MSDC_AUTOCMD12 (0x0001) +#define MSDC_AUTOCMD23 (0x0002) +#define MSDC_AUTOCMD19 (0x0003) + +#define MSDC_EMMC_BOOTMODE0 (0) /* Pull low CMD mode */ +#define MSDC_EMMC_BOOTMODE1 (1) /* Reset CMD mode */ + +enum { + RESP_NONE = 0, + RESP_R1, + RESP_R2, + RESP_R3, + RESP_R4, + RESP_R5, + RESP_R6, + RESP_R7, + RESP_R1B +}; + +/*--------------------------------------------------------------------------*/ +/* Register Offset */ +/*--------------------------------------------------------------------------*/ +#define OFFSET_MSDC_CFG (0x0) +#define OFFSET_MSDC_IOCON (0x04) +#define OFFSET_MSDC_PS (0x08) +#define OFFSET_MSDC_INT (0x0c) +#define OFFSET_MSDC_INTEN (0x10) +#define OFFSET_MSDC_FIFOCS (0x14) +#define OFFSET_MSDC_TXDATA (0x18) +#define OFFSET_MSDC_RXDATA (0x1c) +#define OFFSET_SDC_CFG (0x30) +#define OFFSET_SDC_CMD (0x34) +#define OFFSET_SDC_ARG (0x38) +#define OFFSET_SDC_STS (0x3c) +#define OFFSET_SDC_RESP0 (0x40) +#define OFFSET_SDC_RESP1 (0x44) +#define OFFSET_SDC_RESP2 (0x48) +#define OFFSET_SDC_RESP3 (0x4c) +#define OFFSET_SDC_BLK_NUM (0x50) +#define OFFSET_SDC_CSTS (0x58) +#define OFFSET_SDC_CSTS_EN (0x5c) +#define OFFSET_SDC_DCRC_STS (0x60) +#define OFFSET_EMMC_CFG0 (0x70) +#define OFFSET_EMMC_CFG1 (0x74) +#define OFFSET_EMMC_STS (0x78) +#define OFFSET_EMMC_IOCON (0x7c) +#define OFFSET_SDC_ACMD_RESP (0x80) +#define OFFSET_SDC_ACMD19_TRG (0x84) +#define OFFSET_SDC_ACMD19_STS (0x88) +#define OFFSET_MSDC_DMA_SA (0x90) +#define OFFSET_MSDC_DMA_CA (0x94) +#define OFFSET_MSDC_DMA_CTRL (0x98) +#define OFFSET_MSDC_DMA_CFG (0x9c) +#define OFFSET_MSDC_DBG_SEL (0xa0) +#define OFFSET_MSDC_DBG_OUT (0xa4) +#define OFFSET_MSDC_PATCH_BIT (0xb0) +#define OFFSET_MSDC_PATCH_BIT1 (0xb4) +#define OFFSET_MSDC_PAD_CTL0 (0xe0) +#define OFFSET_MSDC_PAD_CTL1 (0xe4) +#define OFFSET_MSDC_PAD_CTL2 (0xe8) +#define OFFSET_MSDC_PAD_TUNE (0xec) +#define OFFSET_MSDC_DAT_RDDLY0 (0xf0) +#define OFFSET_MSDC_DAT_RDDLY1 (0xf4) +#define OFFSET_MSDC_HW_DBG (0xf8) +#define OFFSET_MSDC_VERSION (0x100) +#define OFFSET_MSDC_ECO_VER (0x104) + +/*--------------------------------------------------------------------------*/ +/* Register Address */ +/*--------------------------------------------------------------------------*/ + +/* common register */ +#define MSDC_CFG REG_ADDR(MSDC_CFG) +#define MSDC_IOCON REG_ADDR(MSDC_IOCON) +#define MSDC_PS REG_ADDR(MSDC_PS) +#define MSDC_INT REG_ADDR(MSDC_INT) +#define MSDC_INTEN REG_ADDR(MSDC_INTEN) +#define MSDC_FIFOCS REG_ADDR(MSDC_FIFOCS) +#define MSDC_TXDATA REG_ADDR(MSDC_TXDATA) +#define MSDC_RXDATA REG_ADDR(MSDC_RXDATA) +#define MSDC_PATCH_BIT0 REG_ADDR(MSDC_PATCH_BIT) + +/* sdmmc register */ +#define SDC_CFG REG_ADDR(SDC_CFG) +#define SDC_CMD REG_ADDR(SDC_CMD) +#define SDC_ARG REG_ADDR(SDC_ARG) +#define SDC_STS REG_ADDR(SDC_STS) +#define SDC_RESP0 REG_ADDR(SDC_RESP0) +#define SDC_RESP1 REG_ADDR(SDC_RESP1) +#define SDC_RESP2 REG_ADDR(SDC_RESP2) +#define SDC_RESP3 REG_ADDR(SDC_RESP3) +#define SDC_BLK_NUM REG_ADDR(SDC_BLK_NUM) +#define SDC_CSTS REG_ADDR(SDC_CSTS) +#define SDC_CSTS_EN REG_ADDR(SDC_CSTS_EN) +#define SDC_DCRC_STS REG_ADDR(SDC_DCRC_STS) + +/* emmc register*/ +#define EMMC_CFG0 REG_ADDR(EMMC_CFG0) +#define EMMC_CFG1 REG_ADDR(EMMC_CFG1) +#define EMMC_STS REG_ADDR(EMMC_STS) +#define EMMC_IOCON REG_ADDR(EMMC_IOCON) + +/* auto command register */ +#define SDC_ACMD_RESP REG_ADDR(SDC_ACMD_RESP) +#define SDC_ACMD19_TRG REG_ADDR(SDC_ACMD19_TRG) +#define SDC_ACMD19_STS REG_ADDR(SDC_ACMD19_STS) + +/* dma register */ +#define MSDC_DMA_SA REG_ADDR(MSDC_DMA_SA) +#define MSDC_DMA_CA REG_ADDR(MSDC_DMA_CA) +#define MSDC_DMA_CTRL REG_ADDR(MSDC_DMA_CTRL) +#define MSDC_DMA_CFG REG_ADDR(MSDC_DMA_CFG) + +/* pad ctrl register */ +#define MSDC_PAD_CTL0 REG_ADDR(MSDC_PAD_CTL0) +#define MSDC_PAD_CTL1 REG_ADDR(MSDC_PAD_CTL1) +#define MSDC_PAD_CTL2 REG_ADDR(MSDC_PAD_CTL2) + +/* data read delay */ +#define MSDC_DAT_RDDLY0 REG_ADDR(MSDC_DAT_RDDLY0) +#define MSDC_DAT_RDDLY1 REG_ADDR(MSDC_DAT_RDDLY1) + +/* debug register */ +#define MSDC_DBG_SEL REG_ADDR(MSDC_DBG_SEL) +#define MSDC_DBG_OUT REG_ADDR(MSDC_DBG_OUT) + +/* misc register */ +#define MSDC_PATCH_BIT REG_ADDR(MSDC_PATCH_BIT) +#define MSDC_PATCH_BIT1 REG_ADDR(MSDC_PATCH_BIT1) +#define MSDC_PAD_TUNE REG_ADDR(MSDC_PAD_TUNE) +#define MSDC_HW_DBG REG_ADDR(MSDC_HW_DBG) +#define MSDC_VERSION REG_ADDR(MSDC_VERSION) +#define MSDC_ECO_VER REG_ADDR(MSDC_ECO_VER) /* ECO Version */ + +/*--------------------------------------------------------------------------*/ +/* Register Mask */ +/*--------------------------------------------------------------------------*/ + +/* MSDC_CFG mask */ +#define MSDC_CFG_MODE (0x1 << 0) /* RW */ +#define MSDC_CFG_CKPDN (0x1 << 1) /* RW */ +#define MSDC_CFG_RST (0x1 << 2) /* RW */ +#define MSDC_CFG_PIO (0x1 << 3) /* RW */ +#define MSDC_CFG_CKDRVEN (0x1 << 4) /* RW */ +#define MSDC_CFG_BV18SDT (0x1 << 5) /* RW */ +#define MSDC_CFG_BV18PSS (0x1 << 6) /* R */ +#define MSDC_CFG_CKSTB (0x1 << 7) /* R */ +#define MSDC_CFG_CKDIV (0xff << 8) /* RW */ +#define MSDC_CFG_CKMOD (0x3 << 16) /* RW */ + +/* MSDC_IOCON mask */ +#define MSDC_IOCON_SDR104CKS (0x1 << 0) /* RW */ +#define MSDC_IOCON_RSPL (0x1 << 1) /* RW */ +#define MSDC_IOCON_DSPL (0x1 << 2) /* RW */ +#define MSDC_IOCON_DDLSEL (0x1 << 3) /* RW */ +#define MSDC_IOCON_DDR50CKD (0x1 << 4) /* RW */ +#define MSDC_IOCON_DSPLSEL (0x1 << 5) /* RW */ +#define MSDC_IOCON_D0SPL (0x1 << 16) /* RW */ +#define MSDC_IOCON_D1SPL (0x1 << 17) /* RW */ +#define MSDC_IOCON_D2SPL (0x1 << 18) /* RW */ +#define MSDC_IOCON_D3SPL (0x1 << 19) /* RW */ +#define MSDC_IOCON_D4SPL (0x1 << 20) /* RW */ +#define MSDC_IOCON_D5SPL (0x1 << 21) /* RW */ +#define MSDC_IOCON_D6SPL (0x1 << 22) /* RW */ +#define MSDC_IOCON_D7SPL (0x1 << 23) /* RW */ +#define MSDC_IOCON_RISCSZ (0x3 << 24) /* RW */ + +/* MSDC_PS mask */ +#define MSDC_PS_CDEN (0x1 << 0) /* RW */ +#define MSDC_PS_CDSTS (0x1 << 1) /* R */ +#define MSDC_PS_CDDEBOUNCE (0xf << 12) /* RW */ +#define MSDC_PS_DAT (0xff << 16) /* R */ +#define MSDC_PS_CMD (0x1 << 24) /* R */ +#define MSDC_PS_WP (0x1UL<< 31) /* R */ + +/* MSDC_INT mask */ +#define MSDC_INT_MMCIRQ (0x1 << 0) /* W1C */ +#define MSDC_INT_CDSC (0x1 << 1) /* W1C */ +#define MSDC_INT_ACMDRDY (0x1 << 3) /* W1C */ +#define MSDC_INT_ACMDTMO (0x1 << 4) /* W1C */ +#define MSDC_INT_ACMDCRCERR (0x1 << 5) /* W1C */ +#define MSDC_INT_DMAQ_EMPTY (0x1 << 6) /* W1C */ +#define MSDC_INT_SDIOIRQ (0x1 << 7) /* W1C */ +#define MSDC_INT_CMDRDY (0x1 << 8) /* W1C */ +#define MSDC_INT_CMDTMO (0x1 << 9) /* W1C */ +#define MSDC_INT_RSPCRCERR (0x1 << 10) /* W1C */ +#define MSDC_INT_CSTA (0x1 << 11) /* R */ +#define MSDC_INT_XFER_COMPL (0x1 << 12) /* W1C */ +#define MSDC_INT_DXFER_DONE (0x1 << 13) /* W1C */ +#define MSDC_INT_DATTMO (0x1 << 14) /* W1C */ +#define MSDC_INT_DATCRCERR (0x1 << 15) /* W1C */ +#define MSDC_INT_ACMD19_DONE (0x1 << 16) /* W1C */ + +/* MSDC_INTEN mask */ +#define MSDC_INTEN_MMCIRQ (0x1 << 0) /* RW */ +#define MSDC_INTEN_CDSC (0x1 << 1) /* RW */ +#define MSDC_INTEN_ACMDRDY (0x1 << 3) /* RW */ +#define MSDC_INTEN_ACMDTMO (0x1 << 4) /* RW */ +#define MSDC_INTEN_ACMDCRCERR (0x1 << 5) /* RW */ +#define MSDC_INTEN_DMAQ_EMPTY (0x1 << 6) /* RW */ +#define MSDC_INTEN_SDIOIRQ (0x1 << 7) /* RW */ +#define MSDC_INTEN_CMDRDY (0x1 << 8) /* RW */ +#define MSDC_INTEN_CMDTMO (0x1 << 9) /* RW */ +#define MSDC_INTEN_RSPCRCERR (0x1 << 10) /* RW */ +#define MSDC_INTEN_CSTA (0x1 << 11) /* RW */ +#define MSDC_INTEN_XFER_COMPL (0x1 << 12) /* RW */ +#define MSDC_INTEN_DXFER_DONE (0x1 << 13) /* RW */ +#define MSDC_INTEN_DATTMO (0x1 << 14) /* RW */ +#define MSDC_INTEN_DATCRCERR (0x1 << 15) /* RW */ +#define MSDC_INTEN_ACMD19_DONE (0x1 << 16) /* RW */ + +/* MSDC_FIFOCS mask */ +#define MSDC_FIFOCS_RXCNT (0xff << 0) /* R */ +#define MSDC_FIFOCS_TXCNT (0xff << 16) /* R */ +#define MSDC_FIFOCS_CLR (0x1UL<< 31) /* RW */ + +/* SDC_CFG mask */ +#define SDC_CFG_SDIOINTWKUP (0x1 << 0) /* RW */ +#define SDC_CFG_INSWKUP (0x1 << 1) /* RW */ +#define SDC_CFG_BUSWIDTH (0x3 << 16) /* RW */ +#define SDC_CFG_SDIO (0x1 << 19) /* RW */ +#define SDC_CFG_SDIOIDE (0x1 << 20) /* RW */ +#define SDC_CFG_INTATGAP (0x1 << 21) /* RW */ +#define SDC_CFG_DTOC (0xffUL << 24) /* RW */ + +/* SDC_CMD mask */ +#define SDC_CMD_OPC (0x3f << 0) /* RW */ +#define SDC_CMD_BRK (0x1 << 6) /* RW */ +#define SDC_CMD_RSPTYP (0x7 << 7) /* RW */ +#define SDC_CMD_DTYP (0x3 << 11) /* RW */ +#define SDC_CMD_DTYP (0x3 << 11) /* RW */ +#define SDC_CMD_RW (0x1 << 13) /* RW */ +#define SDC_CMD_STOP (0x1 << 14) /* RW */ +#define SDC_CMD_GOIRQ (0x1 << 15) /* RW */ +#define SDC_CMD_BLKLEN (0xfff<< 16) /* RW */ +#define SDC_CMD_AUTOCMD (0x3 << 28) /* RW */ +#define SDC_CMD_VOLSWTH (0x1 << 30) /* RW */ + +/* SDC_STS mask */ +#define SDC_STS_SDCBUSY (0x1 << 0) /* RW */ +#define SDC_STS_CMDBUSY (0x1 << 1) /* RW */ +#define SDC_STS_SWR_COMPL (0x1 << 31) /* RW */ + +/* SDC_DCRC_STS mask */ +#define SDC_DCRC_STS_NEG (0xf << 8) /* RO */ +#define SDC_DCRC_STS_POS (0xff << 0) /* RO */ + +/* EMMC_CFG0 mask */ +#define EMMC_CFG0_BOOTSTART (0x1 << 0) /* W */ +#define EMMC_CFG0_BOOTSTOP (0x1 << 1) /* W */ +#define EMMC_CFG0_BOOTMODE (0x1 << 2) /* RW */ +#define EMMC_CFG0_BOOTACKDIS (0x1 << 3) /* RW */ +#define EMMC_CFG0_BOOTWDLY (0x7 << 12) /* RW */ +#define EMMC_CFG0_BOOTSUPP (0x1 << 15) /* RW */ + +/* EMMC_CFG1 mask */ +#define EMMC_CFG1_BOOTDATTMC (0xfffff << 0) /* RW */ +#define EMMC_CFG1_BOOTACKTMC (0xfffUL << 20) /* RW */ + +/* EMMC_STS mask */ +#define EMMC_STS_BOOTCRCERR (0x1 << 0) /* W1C */ +#define EMMC_STS_BOOTACKERR (0x1 << 1) /* W1C */ +#define EMMC_STS_BOOTDATTMO (0x1 << 2) /* W1C */ +#define EMMC_STS_BOOTACKTMO (0x1 << 3) /* W1C */ +#define EMMC_STS_BOOTUPSTATE (0x1 << 4) /* R */ +#define EMMC_STS_BOOTACKRCV (0x1 << 5) /* W1C */ +#define EMMC_STS_BOOTDATRCV (0x1 << 6) /* R */ + +/* EMMC_IOCON mask */ +#define EMMC_IOCON_BOOTRST (0x1 << 0) /* RW */ + +/* SDC_ACMD19_TRG mask */ +#define SDC_ACMD19_TRG_TUNESEL (0xf << 0) /* RW */ + +/* MSDC_DMA_CTRL mask */ +#define MSDC_DMA_CTRL_START (0x1 << 0) /* W */ +#define MSDC_DMA_CTRL_STOP (0x1 << 1) /* W */ +#define MSDC_DMA_CTRL_RESUME (0x1 << 2) /* W */ +#define MSDC_DMA_CTRL_MODE (0x1 << 8) /* RW */ +#define MSDC_DMA_CTRL_LASTBUF (0x1 << 10) /* RW */ +#define MSDC_DMA_CTRL_BRUSTSZ (0x7 << 12) /* RW */ +#define MSDC_DMA_CTRL_XFERSZ (0xffffUL << 16)/* RW */ + +/* MSDC_DMA_CFG mask */ +#define MSDC_DMA_CFG_STS (0x1 << 0) /* R */ +#define MSDC_DMA_CFG_DECSEN (0x1 << 1) /* RW */ +#define MSDC_DMA_CFG_BDCSERR (0x1 << 4) /* R */ +#define MSDC_DMA_CFG_GPDCSERR (0x1 << 5) /* R */ + +/* MSDC_PATCH_BIT mask */ +#define MSDC_PATCH_BIT_WFLSMODE (0x1 << 0) /* RW */ +#define MSDC_PATCH_BIT_ODDSUPP (0x1 << 1) /* RW */ +#define MSDC_PATCH_BIT_CKGEN_CK (0x1 << 6) /* E2: Fixed to 1 */ +#define MSDC_PATCH_BIT_IODSSEL (0x1 << 16) /* RW */ +#define MSDC_PATCH_BIT_IOINTSEL (0x1 << 17) /* RW */ +#define MSDC_PATCH_BIT_BUSYDLY (0xf << 18) /* RW */ +#define MSDC_PATCH_BIT_WDOD (0xf << 22) /* RW */ +#define MSDC_PATCH_BIT_IDRTSEL (0x1 << 26) /* RW */ +#define MSDC_PATCH_BIT_CMDFSEL (0x1 << 27) /* RW */ +#define MSDC_PATCH_BIT_INTDLSEL (0x1 << 28) /* RW */ +#define MSDC_PATCH_BIT_SPCPUSH (0x1 << 29) /* RW */ +#define MSDC_PATCH_BIT_DECRCTMO (0x1 << 30) /* RW */ + +/* MSDC_PATCH_BIT1 mask */ +#define MSDC_PATCH_BIT1_WRDAT_CRCS (0x7 << 3) +#define MSDC_PATCH_BIT1_CMD_RSP (0x7 << 0) + +/* MSDC_PAD_CTL0 mask */ +#define MSDC_PAD_CTL0_CLKDRVN (0x7 << 0) /* RW */ +#define MSDC_PAD_CTL0_CLKDRVP (0x7 << 4) /* RW */ +#define MSDC_PAD_CTL0_CLKSR (0x1 << 8) /* RW */ +#define MSDC_PAD_CTL0_CLKPD (0x1 << 16) /* RW */ +#define MSDC_PAD_CTL0_CLKPU (0x1 << 17) /* RW */ +#define MSDC_PAD_CTL0_CLKSMT (0x1 << 18) /* RW */ +#define MSDC_PAD_CTL0_CLKIES (0x1 << 19) /* RW */ +#define MSDC_PAD_CTL0_CLKTDSEL (0xf << 20) /* RW */ +#define MSDC_PAD_CTL0_CLKRDSEL (0xffUL<< 24) /* RW */ + +/* MSDC_PAD_CTL1 mask */ +#define MSDC_PAD_CTL1_CMDDRVN (0x7 << 0) /* RW */ +#define MSDC_PAD_CTL1_CMDDRVP (0x7 << 4) /* RW */ +#define MSDC_PAD_CTL1_CMDSR (0x1 << 8) /* RW */ +#define MSDC_PAD_CTL1_CMDPD (0x1 << 16) /* RW */ +#define MSDC_PAD_CTL1_CMDPU (0x1 << 17) /* RW */ +#define MSDC_PAD_CTL1_CMDSMT (0x1 << 18) /* RW */ +#define MSDC_PAD_CTL1_CMDIES (0x1 << 19) /* RW */ +#define MSDC_PAD_CTL1_CMDTDSEL (0xf << 20) /* RW */ +#define MSDC_PAD_CTL1_CMDRDSEL (0xffUL<< 24) /* RW */ + +/* MSDC_PAD_CTL2 mask */ +#define MSDC_PAD_CTL2_DATDRVN (0x7 << 0) /* RW */ +#define MSDC_PAD_CTL2_DATDRVP (0x7 << 4) /* RW */ +#define MSDC_PAD_CTL2_DATSR (0x1 << 8) /* RW */ +#define MSDC_PAD_CTL2_DATPD (0x1 << 16) /* RW */ +#define MSDC_PAD_CTL2_DATPU (0x1 << 17) /* RW */ +#define MSDC_PAD_CTL2_DATIES (0x1 << 19) /* RW */ +#define MSDC_PAD_CTL2_DATSMT (0x1 << 18) /* RW */ +#define MSDC_PAD_CTL2_DATTDSEL (0xf << 20) /* RW */ +#define MSDC_PAD_CTL2_DATRDSEL (0xffUL<< 24) /* RW */ + +/* MSDC_PAD_TUNE mask */ +#define MSDC_PAD_TUNE_DATWRDLY (0x1F << 0) /* RW */ +#define MSDC_PAD_TUNE_DATRRDLY (0x1F << 8) /* RW */ +#define MSDC_PAD_TUNE_CMDRDLY (0x1F << 16) /* RW */ +#define MSDC_PAD_TUNE_CMDRRDLY (0x1FUL << 22) /* RW */ +#define MSDC_PAD_TUNE_CLKTXDLY (0x1FUL << 27) /* RW */ + +/* MSDC_DAT_RDDLY0/1 mask */ +#define MSDC_DAT_RDDLY0_D0 (0x1F << 0) /* RW */ +#define MSDC_DAT_RDDLY0_D1 (0x1F << 8) /* RW */ +#define MSDC_DAT_RDDLY0_D2 (0x1F << 16) /* RW */ +#define MSDC_DAT_RDDLY0_D3 (0x1F << 24) /* RW */ + +#define MSDC_DAT_RDDLY1_D4 (0x1F << 0) /* RW */ +#define MSDC_DAT_RDDLY1_D5 (0x1F << 8) /* RW */ +#define MSDC_DAT_RDDLY1_D6 (0x1F << 16) /* RW */ +#define MSDC_DAT_RDDLY1_D7 (0x1F << 24) /* RW */ + +#define MSDC_CKGEN_MSDC_DLY_SEL (0x1F<<10) +#define MSDC_INT_DAT_LATCH_CK_SEL (0x7<<7) +#define MSDC_CKGEN_MSDC_CK_SEL (0x1<<6) +#define CARD_READY_FOR_DATA (1<<8) +#define CARD_CURRENT_STATE(x) ((x&0x00001E00)>>9) + +/*--------------------------------------------------------------------------*/ +/* Descriptor Structure */ +/*--------------------------------------------------------------------------*/ +typedef struct { + u32 hwo:1; /* could be changed by hw */ + u32 bdp:1; + u32 rsv0:6; + u32 chksum:8; + u32 intr:1; + u32 rsv1:15; + void *next; + void *ptr; + u32 buflen:16; + u32 extlen:8; + u32 rsv2:8; + u32 arg; + u32 blknum; + u32 cmd; +} gpd_t; + +typedef struct { + u32 eol:1; + u32 rsv0:7; + u32 chksum:8; + u32 rsv1:1; + u32 blkpad:1; + u32 dwpad:1; + u32 rsv2:13; + void *next; + void *ptr; + u32 buflen:16; + u32 rsv3:16; +} bd_t; + +/*--------------------------------------------------------------------------*/ +/* Register Debugging Structure */ +/*--------------------------------------------------------------------------*/ + +typedef struct { + u32 msdc:1; + u32 ckpwn:1; + u32 rst:1; + u32 pio:1; + u32 ckdrven:1; + u32 start18v:1; + u32 pass18v:1; + u32 ckstb:1; + u32 ckdiv:8; + u32 ckmod:2; + u32 pad:14; +} msdc_cfg_reg; +typedef struct { + u32 sdr104cksel:1; + u32 rsmpl:1; + u32 dsmpl:1; + u32 ddlysel:1; + u32 ddr50ckd:1; + u32 dsplsel:1; + u32 pad1:10; + u32 d0spl:1; + u32 d1spl:1; + u32 d2spl:1; + u32 d3spl:1; + u32 d4spl:1; + u32 d5spl:1; + u32 d6spl:1; + u32 d7spl:1; + u32 riscsz:1; + u32 pad2:7; +} msdc_iocon_reg; +typedef struct { + u32 cden:1; + u32 cdsts:1; + u32 pad1:10; + u32 cddebounce:4; + u32 dat:8; + u32 cmd:1; + u32 pad2:6; + u32 wp:1; +} msdc_ps_reg; +typedef struct { + u32 mmcirq:1; + u32 cdsc:1; + u32 pad1:1; + u32 atocmdrdy:1; + u32 atocmdtmo:1; + u32 atocmdcrc:1; + u32 dmaqempty:1; + u32 sdioirq:1; + u32 cmdrdy:1; + u32 cmdtmo:1; + u32 rspcrc:1; + u32 csta:1; + u32 xfercomp:1; + u32 dxferdone:1; + u32 dattmo:1; + u32 datcrc:1; + u32 atocmd19done:1; + u32 pad2:15; +} msdc_int_reg; +typedef struct { + u32 mmcirq:1; + u32 cdsc:1; + u32 pad1:1; + u32 atocmdrdy:1; + u32 atocmdtmo:1; + u32 atocmdcrc:1; + u32 dmaqempty:1; + u32 sdioirq:1; + u32 cmdrdy:1; + u32 cmdtmo:1; + u32 rspcrc:1; + u32 csta:1; + u32 xfercomp:1; + u32 dxferdone:1; + u32 dattmo:1; + u32 datcrc:1; + u32 atocmd19done:1; + u32 pad2:15; +} msdc_inten_reg; +typedef struct { + u32 rxcnt:8; + u32 pad1:8; + u32 txcnt:8; + u32 pad2:7; + u32 clr:1; +} msdc_fifocs_reg; +typedef struct { + u32 val; +} msdc_txdat_reg; +typedef struct { + u32 val; +} msdc_rxdat_reg; +typedef struct { + u32 sdiowkup:1; + u32 inswkup:1; + u32 pad1:14; + u32 buswidth:2; + u32 pad2:1; + u32 sdio:1; + u32 sdioide:1; + u32 intblkgap:1; + u32 pad4:2; + u32 dtoc:8; +} sdc_cfg_reg; +typedef struct { + u32 cmd:6; + u32 brk:1; + u32 rsptyp:3; + u32 pad1:1; + u32 dtype:2; + u32 rw:1; + u32 stop:1; + u32 goirq:1; + u32 blklen:12; + u32 atocmd:2; + u32 volswth:1; + u32 pad2:1; +} sdc_cmd_reg; +typedef struct { + u32 arg; +} sdc_arg_reg; +typedef struct { + u32 sdcbusy:1; + u32 cmdbusy:1; + u32 pad:29; + u32 swrcmpl:1; +} sdc_sts_reg; +typedef struct { + u32 val; +} sdc_resp0_reg; +typedef struct { + u32 val; +} sdc_resp1_reg; +typedef struct { + u32 val; +} sdc_resp2_reg; +typedef struct { + u32 val; +} sdc_resp3_reg; +typedef struct { + u32 num; +} sdc_blknum_reg; +typedef struct { + u32 sts; +} sdc_csts_reg; +typedef struct { + u32 sts; +} sdc_cstsen_reg; +typedef struct { + u32 datcrcsts:8; + u32 ddrcrcsts:4; + u32 pad:20; +} sdc_datcrcsts_reg; +typedef struct { + u32 bootstart:1; + u32 bootstop:1; + u32 bootmode:1; + u32 pad1:9; + u32 bootwaidly:3; + u32 bootsupp:1; + u32 pad2:16; +} emmc_cfg0_reg; +typedef struct { + u32 bootcrctmc:16; + u32 pad:4; + u32 bootacktmc:12; +} emmc_cfg1_reg; +typedef struct { + u32 bootcrcerr:1; + u32 bootackerr:1; + u32 bootdattmo:1; + u32 bootacktmo:1; + u32 bootupstate:1; + u32 bootackrcv:1; + u32 bootdatrcv:1; + u32 pad:25; +} emmc_sts_reg; +typedef struct { + u32 bootrst:1; + u32 pad:31; +} emmc_iocon_reg; +typedef struct { + u32 val; +} msdc_acmd_resp_reg; +typedef struct { + u32 tunesel:4; + u32 pad:28; +} msdc_acmd19_trg_reg; +typedef struct { + u32 val; +} msdc_acmd19_sts_reg; +typedef struct { + u32 addr; +} msdc_dma_sa_reg; +typedef struct { + u32 addr; +} msdc_dma_ca_reg; +typedef struct { + u32 start:1; + u32 stop:1; + u32 resume:1; + u32 pad1:5; + u32 mode:1; + u32 pad2:1; + u32 lastbuf:1; + u32 pad3:1; + u32 brustsz:3; + u32 pad4:1; + u32 xfersz:16; +} msdc_dma_ctrl_reg; +typedef struct { + u32 status:1; + u32 decsen:1; + u32 pad1:2; + u32 bdcsen:1; + u32 gpdcsen:1; + u32 pad2:26; +} msdc_dma_cfg_reg; +typedef struct { + u32 sel:16; + u32 pad2:16; +} msdc_dbg_sel_reg; +typedef struct { + u32 val; +} msdc_dbg_out_reg; +typedef struct { + u32 clkdrvn:3; + u32 rsv0:1; + u32 clkdrvp:3; + u32 rsv1:1; + u32 clksr:1; + u32 rsv2:7; + u32 clkpd:1; + u32 clkpu:1; + u32 clksmt:1; + u32 clkies:1; + u32 clktdsel:4; + u32 clkrdsel:8; +} msdc_pad_ctl0_reg; +typedef struct { + u32 cmddrvn:3; + u32 rsv0:1; + u32 cmddrvp:3; + u32 rsv1:1; + u32 cmdsr:1; + u32 rsv2:7; + u32 cmdpd:1; + u32 cmdpu:1; + u32 cmdsmt:1; + u32 cmdies:1; + u32 cmdtdsel:4; + u32 cmdrdsel:8; +} msdc_pad_ctl1_reg; +typedef struct { + u32 datdrvn:3; + u32 rsv0:1; + u32 datdrvp:3; + u32 rsv1:1; + u32 datsr:1; + u32 rsv2:7; + u32 datpd:1; + u32 datpu:1; + u32 datsmt:1; + u32 daties:1; + u32 dattdsel:4; + u32 datrdsel:8; +} msdc_pad_ctl2_reg; +typedef struct { + u32 wrrxdly:3; + u32 pad1:5; + u32 rdrxdly:8; + u32 pad2:16; +} msdc_pad_tune_reg; +typedef struct { + u32 dat0:5; + u32 rsv0:3; + u32 dat1:5; + u32 rsv1:3; + u32 dat2:5; + u32 rsv2:3; + u32 dat3:5; + u32 rsv3:3; +} msdc_dat_rddly0; +typedef struct { + u32 dat4:5; + u32 rsv4:3; + u32 dat5:5; + u32 rsv5:3; + u32 dat6:5; + u32 rsv6:3; + u32 dat7:5; + u32 rsv7:3; +} msdc_dat_rddly1; +typedef struct { + u32 dbg0sel:8; + u32 dbg1sel:6; + u32 pad1:2; + u32 dbg2sel:6; + u32 pad2:2; + u32 dbg3sel:6; + u32 pad3:2; +} msdc_hw_dbg_reg; +typedef struct { + u32 val; +} msdc_version_reg; +typedef struct { + u32 val; +} msdc_eco_ver_reg; + +struct msdc_regs { + msdc_cfg_reg msdc_cfg; /* base+0x00h */ + msdc_iocon_reg msdc_iocon; /* base+0x04h */ + msdc_ps_reg msdc_ps; /* base+0x08h */ + msdc_int_reg msdc_int; /* base+0x0ch */ + msdc_inten_reg msdc_inten; /* base+0x10h */ + msdc_fifocs_reg msdc_fifocs; /* base+0x14h */ + msdc_txdat_reg msdc_txdat; /* base+0x18h */ + msdc_rxdat_reg msdc_rxdat; /* base+0x1ch */ + u32 rsv1[4]; + sdc_cfg_reg sdc_cfg; /* base+0x30h */ + sdc_cmd_reg sdc_cmd; /* base+0x34h */ + sdc_arg_reg sdc_arg; /* base+0x38h */ + sdc_sts_reg sdc_sts; /* base+0x3ch */ + sdc_resp0_reg sdc_resp0; /* base+0x40h */ + sdc_resp1_reg sdc_resp1; /* base+0x44h */ + sdc_resp2_reg sdc_resp2; /* base+0x48h */ + sdc_resp3_reg sdc_resp3; /* base+0x4ch */ + sdc_blknum_reg sdc_blknum; /* base+0x50h */ + u32 rsv2[1]; + sdc_csts_reg sdc_csts; /* base+0x58h */ + sdc_cstsen_reg sdc_cstsen; /* base+0x5ch */ + sdc_datcrcsts_reg sdc_dcrcsta; /* base+0x60h */ + u32 rsv3[3]; + emmc_cfg0_reg emmc_cfg0; /* base+0x70h */ + emmc_cfg1_reg emmc_cfg1; /* base+0x74h */ + emmc_sts_reg emmc_sts; /* base+0x78h */ + emmc_iocon_reg emmc_iocon; /* base+0x7ch */ + msdc_acmd_resp_reg acmd_resp; /* base+0x80h */ + msdc_acmd19_trg_reg acmd19_trg; /* base+0x84h */ + msdc_acmd19_sts_reg acmd19_sts; /* base+0x88h */ + u32 rsv4[1]; + msdc_dma_sa_reg dma_sa; /* base+0x90h */ + msdc_dma_ca_reg dma_ca; /* base+0x94h */ + msdc_dma_ctrl_reg dma_ctrl; /* base+0x98h */ + msdc_dma_cfg_reg dma_cfg; /* base+0x9ch */ + msdc_dbg_sel_reg dbg_sel; /* base+0xa0h */ + msdc_dbg_out_reg dbg_out; /* base+0xa4h */ + u32 rsv5[2]; + u32 patch0; /* base+0xb0h */ + u32 patch1; /* base+0xb4h */ + u32 rsv6[10]; + msdc_pad_ctl0_reg pad_ctl0; /* base+0xe0h */ + msdc_pad_ctl1_reg pad_ctl1; /* base+0xe4h */ + msdc_pad_ctl2_reg pad_ctl2; /* base+0xe8h */ + msdc_pad_tune_reg pad_tune; /* base+0xech */ + msdc_dat_rddly0 dat_rddly0; /* base+0xf0h */ + msdc_dat_rddly1 dat_rddly1; /* base+0xf4h */ + msdc_hw_dbg_reg hw_dbg; /* base+0xf8h */ + u32 rsv7[1]; + msdc_version_reg version; /* base+0x100h */ + msdc_eco_ver_reg eco_ver; /* base+0x104h */ +}; + +struct scatterlist_ex { + u32 cmd; + u32 arg; + u32 sglen; + struct scatterlist *sg; +}; + +#define DMA_FLAG_NONE (0x00000000) +#define DMA_FLAG_EN_CHKSUM (0x00000001) +#define DMA_FLAG_PAD_BLOCK (0x00000002) +#define DMA_FLAG_PAD_DWORD (0x00000004) + +struct msdc_dma { + u32 flags; /* flags */ + u32 xfersz; /* xfer size in bytes */ + u32 sglen; /* size of scatter list */ + u32 blklen; /* block size */ + struct scatterlist *sg; /* I/O scatter list */ + struct scatterlist_ex *esg; /* extended I/O scatter list */ + u8 mode; /* dma mode */ + u8 burstsz; /* burst size */ + u8 intr; /* dma done interrupt */ + u8 padding; /* padding */ + u32 cmd; /* enhanced mode command */ + u32 arg; /* enhanced mode arg */ + u32 rsp; /* enhanced mode command response */ + u32 autorsp; /* auto command response */ + + gpd_t *gpd; /* pointer to gpd array */ + bd_t *bd; /* pointer to bd array */ + dma_addr_t gpd_addr; /* the physical address of gpd array */ + dma_addr_t bd_addr; /* the physical address of bd array */ + u32 used_gpd; /* the number of used gpd elements */ + u32 used_bd; /* the number of used bd elements */ +}; + +struct msdc_host +{ + struct msdc_hw *hw; + + struct mmc_host *mmc; /* mmc structure */ + struct mmc_command *cmd; + struct mmc_data *data; + struct mmc_request *mrq; + int cmd_rsp; + int cmd_rsp_done; + int cmd_r1b_done; + + int error; + spinlock_t lock; /* mutex */ + struct semaphore sem; + + u32 blksz; /* host block size */ + u32 base; /* host base address */ + int id; /* host id */ + int pwr_ref; /* core power reference count */ + + u32 xfer_size; /* total transferred size */ + + struct msdc_dma dma; /* dma channel */ + u32 dma_addr; /* dma transfer address */ + u32 dma_left_size; /* dma transfer left size */ + u32 dma_xfer_size; /* dma transfer size in bytes */ + int dma_xfer; /* dma transfer mode */ + + u32 timeout_ns; /* data timeout ns */ + u32 timeout_clks; /* data timeout clks */ + + atomic_t abort; /* abort transfer */ + + int irq; /* host interrupt */ + + struct tasklet_struct card_tasklet; +#if 0 + struct work_struct card_workqueue; +#else + struct delayed_work card_delaywork; +#endif + + struct completion cmd_done; + struct completion xfer_done; + struct pm_message pm_state; + + u32 mclk; /* mmc subsystem clock */ + u32 hclk; /* host clock speed */ + u32 sclk; /* SD/MS clock speed */ + u8 core_clkon; /* Host core clock on ? */ + u8 card_clkon; /* Card clock on ? */ + u8 core_power; /* core power */ + u8 power_mode; /* host power mode */ + u8 card_inserted; /* card inserted ? */ + u8 suspend; /* host suspended ? */ + u8 reserved; + u8 app_cmd; /* for app command */ + u32 app_cmd_arg; + u64 starttime; +}; + +static inline unsigned int uffs(unsigned int x) +{ + unsigned int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} +#define sdr_read8(reg) __raw_readb(reg) +#define sdr_read16(reg) __raw_readw(reg) +#define sdr_read32(reg) __raw_readl(reg) +#define sdr_write8(reg,val) __raw_writeb(val,reg) +#define sdr_write16(reg,val) __raw_writew(val,reg) +#define sdr_write32(reg,val) __raw_writel(val,reg) + +#define sdr_set_bits(reg,bs) ((*(volatile u32*)(reg)) |= (u32)(bs)) +#define sdr_clr_bits(reg,bs) ((*(volatile u32*)(reg)) &= ~((u32)(bs))) + +#define sdr_set_field(reg,field,val) \ + do { \ + volatile unsigned int tv = sdr_read32(reg); \ + tv &= ~(field); \ + tv |= ((val) << (uffs((unsigned int)field) - 1)); \ + sdr_write32(reg,tv); \ + } while(0) +#define sdr_get_field(reg,field,val) \ + do { \ + volatile unsigned int tv = sdr_read32(reg); \ + val = ((tv & (field)) >> (uffs((unsigned int)field) - 1)); \ + } while(0) + +#endif + diff --git a/drivers/staging/mt7621-mmc/sd.c b/drivers/staging/mt7621-mmc/sd.c new file mode 100644 index 000000000000..a1d0173eba56 --- /dev/null +++ b/drivers/staging/mt7621-mmc/sd.c @@ -0,0 +1,3074 @@ +/* Copyright Statement: + * + * This software/firmware and related documentation ("MediaTek Software") are + * protected under relevant copyright laws. The information contained herein + * is confidential and proprietary to MediaTek Inc. and/or its licensors. + * Without the prior written permission of MediaTek inc. and/or its licensors, + * any reproduction, modification, use or disclosure of MediaTek Software, + * and information contained herein, in whole or in part, shall be strictly prohibited. + * + * MediaTek Inc. (C) 2010. All rights reserved. + * + * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES + * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") + * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON + * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. + * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE + * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR + * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH + * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES + * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES + * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK + * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR + * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND + * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, + * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, + * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO + * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. + * + * The following software/firmware and/or related documentation ("MediaTek Software") + * have been modified by MediaTek Inc. All revisions are subject to any receiver's + * applicable license agreements with MediaTek Inc. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/blkdev.h> +#include <linux/slab.h> +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/mmc/core.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> +#include <linux/mmc/sdio.h> +#include <linux/dma-mapping.h> + +/* +++ by chhung */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/version.h> +#include <linux/pm.h> +#include <linux/of.h> + +#define MSDC_SMPL_FALLING (1) +#define MSDC_CD_PIN_EN (1 << 0) /* card detection pin is wired */ +#define MSDC_WP_PIN_EN (1 << 1) /* write protection pin is wired */ +#define MSDC_REMOVABLE (1 << 5) /* removable slot */ +#define MSDC_SYS_SUSPEND (1 << 6) /* suspended by system */ +#define MSDC_HIGHSPEED (1 << 7) + +//#define IRQ_SDC 14 //MT7620 /*FIXME*/ +#ifdef CONFIG_SOC_MT7621 +#define RALINK_SYSCTL_BASE 0xbe000000 +#define RALINK_MSDC_BASE 0xbe130000 +#else +#define RALINK_SYSCTL_BASE 0xb0000000 +#define RALINK_MSDC_BASE 0xb0130000 +#endif +#define IRQ_SDC 22 /*FIXME*/ + +#include <asm/dma.h> +/* end of +++ */ + + +#include <asm/mach-ralink/ralink_regs.h> + +#if 0 /* --- by chhung */ +#include <mach/board.h> +#include <mach/mt6575_devs.h> +#include <mach/mt6575_typedefs.h> +#include <mach/mt6575_clock_manager.h> +#include <mach/mt6575_pm_ldo.h> +//#include <mach/mt6575_pll.h> +//#include <mach/mt6575_gpio.h> +//#include <mach/mt6575_gpt_sw.h> +#include <asm/tcm.h> +// #include <mach/mt6575_gpt.h> +#endif /* end of --- */ + +#include "mt6575_sd.h" +#include "dbg.h" + +/* +++ by chhung */ +#include "board.h" +/* end of +++ */ + +#if 0 /* --- by chhung */ +#define isb() __asm__ __volatile__ ("" : : : "memory") +#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \ + : : "r" (0) : "memory") +#define dmb() __asm__ __volatile__ ("" : : : "memory") +#endif /* end of --- */ + +#define DRV_NAME "mtk-sd" + +#define HOST_MAX_NUM (1) /* +/- by chhung */ + +#if defined (CONFIG_SOC_MT7620) +#define HOST_MAX_MCLK (48000000) /* +/- by chhung */ +#elif defined (CONFIG_SOC_MT7621) +#define HOST_MAX_MCLK (50000000) /* +/- by chhung */ +#endif +#define HOST_MIN_MCLK (260000) + +#define HOST_MAX_BLKSZ (2048) + +#define MSDC_OCR_AVAIL (MMC_VDD_28_29 | MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33) + +#define GPIO_PULL_DOWN (0) +#define GPIO_PULL_UP (1) + +#if 0 /* --- by chhung */ +#define MSDC_CLKSRC_REG (0xf100000C) +#define PDN_REG (0xF1000010) +#endif /* end of --- */ + +#define DEFAULT_DEBOUNCE (8) /* 8 cycles */ +#define DEFAULT_DTOC (40) /* data timeout counter. 65536x40 sclk. */ + +#define CMD_TIMEOUT (HZ/10) /* 100ms */ +#define DAT_TIMEOUT (HZ/2 * 5) /* 500ms x5 */ + +#define MAX_DMA_CNT (64 * 1024 - 512) /* a single transaction for WIFI may be 50K*/ + +#define MAX_GPD_NUM (1 + 1) /* one null gpd */ +#define MAX_BD_NUM (1024) +#define MAX_BD_PER_GPD (MAX_BD_NUM) + +#define MAX_HW_SGMTS (MAX_BD_NUM) +#define MAX_PHY_SGMTS (MAX_BD_NUM) +#define MAX_SGMT_SZ (MAX_DMA_CNT) +#define MAX_REQ_SZ (MAX_SGMT_SZ * 8) + +#ifdef MT6575_SD_DEBUG +static struct msdc_regs *msdc_reg[HOST_MAX_NUM]; +#endif + +static int mtk_sw_poll; + +static int cd_active_low = 1; + +//================================= +#define PERI_MSDC0_PDN (15) +//#define PERI_MSDC1_PDN (16) +//#define PERI_MSDC2_PDN (17) +//#define PERI_MSDC3_PDN (18) + +struct msdc_host *msdc_6575_host[] = {NULL,NULL,NULL,NULL}; +#if 0 /* --- by chhung */ +/* gate means clock power down */ +static int g_clk_gate = 0; +#define msdc_gate_clock(id) \ + do { \ + g_clk_gate &= ~(1 << ((id) + PERI_MSDC0_PDN)); \ + } while(0) +/* not like power down register. 1 means clock on. */ +#define msdc_ungate_clock(id) \ + do { \ + g_clk_gate |= 1 << ((id) + PERI_MSDC0_PDN); \ + } while(0) + +// do we need sync object or not +void msdc_clk_status(int * status) +{ + *status = g_clk_gate; +} +#endif /* end of --- */ + +/* +++ by chhung */ +struct msdc_hw msdc0_hw = { + .clk_src = 0, + .cmd_edge = MSDC_SMPL_FALLING, + .data_edge = MSDC_SMPL_FALLING, + .clk_drv = 4, + .cmd_drv = 4, + .dat_drv = 4, + .data_pins = 4, + .data_offset = 0, + .flags = MSDC_SYS_SUSPEND | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED, +// .flags = MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE, +}; + +static struct resource mtk_sd_resources[] = { + [0] = { + .start = RALINK_MSDC_BASE, + .end = RALINK_MSDC_BASE+0x3fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SDC, /*FIXME*/ + .end = IRQ_SDC, /*FIXME*/ + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device mtk_sd_device = { + .name = "mtk-sd", + .id = 0, + .num_resources = ARRAY_SIZE(mtk_sd_resources), + .resource = mtk_sd_resources, +}; +/* end of +++ */ + +static int msdc_rsp[] = { + 0, /* RESP_NONE */ + 1, /* RESP_R1 */ + 2, /* RESP_R2 */ + 3, /* RESP_R3 */ + 4, /* RESP_R4 */ + 1, /* RESP_R5 */ + 1, /* RESP_R6 */ + 1, /* RESP_R7 */ + 7, /* RESP_R1b */ +}; + +/* For Inhanced DMA */ +#define msdc_init_gpd_ex(gpd,extlen,cmd,arg,blknum) \ + do { \ + ((gpd_t*)gpd)->extlen = extlen; \ + ((gpd_t*)gpd)->cmd = cmd; \ + ((gpd_t*)gpd)->arg = arg; \ + ((gpd_t*)gpd)->blknum = blknum; \ + }while(0) + +#define msdc_init_bd(bd, blkpad, dwpad, dptr, dlen) \ + do { \ + BUG_ON(dlen > 0xFFFFUL); \ + ((bd_t*)bd)->blkpad = blkpad; \ + ((bd_t*)bd)->dwpad = dwpad; \ + ((bd_t*)bd)->ptr = (void*)dptr; \ + ((bd_t*)bd)->buflen = dlen; \ + }while(0) + +#define msdc_txfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_TXCNT) >> 16) +#define msdc_rxfifocnt() ((sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_RXCNT) >> 0) +#define msdc_fifo_write32(v) sdr_write32(MSDC_TXDATA, (v)) +#define msdc_fifo_write8(v) sdr_write8(MSDC_TXDATA, (v)) +#define msdc_fifo_read32() sdr_read32(MSDC_RXDATA) +#define msdc_fifo_read8() sdr_read8(MSDC_RXDATA) + + +#define msdc_dma_on() sdr_clr_bits(MSDC_CFG, MSDC_CFG_PIO) +#define msdc_dma_off() sdr_set_bits(MSDC_CFG, MSDC_CFG_PIO) + +#define msdc_retry(expr,retry,cnt) \ + do { \ + int backup = cnt; \ + while (retry) { \ + if (!(expr)) break; \ + if (cnt-- == 0) { \ + retry--; mdelay(1); cnt = backup; \ + } \ + } \ + WARN_ON(retry == 0); \ + } while(0) + +#if 0 /* --- by chhung */ +#define msdc_reset() \ + do { \ + int retry = 3, cnt = 1000; \ + sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \ + dsb(); \ + msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \ + } while(0) +#else +#define msdc_reset() \ + do { \ + int retry = 3, cnt = 1000; \ + sdr_set_bits(MSDC_CFG, MSDC_CFG_RST); \ + msdc_retry(sdr_read32(MSDC_CFG) & MSDC_CFG_RST, retry, cnt); \ + } while(0) +#endif /* end of +/- */ + +#define msdc_clr_int() \ + do { \ + volatile u32 val = sdr_read32(MSDC_INT); \ + sdr_write32(MSDC_INT, val); \ + } while(0) + +#define msdc_clr_fifo() \ + do { \ + int retry = 3, cnt = 1000; \ + sdr_set_bits(MSDC_FIFOCS, MSDC_FIFOCS_CLR); \ + msdc_retry(sdr_read32(MSDC_FIFOCS) & MSDC_FIFOCS_CLR, retry, cnt); \ + } while(0) + +#define msdc_irq_save(val) \ + do { \ + val = sdr_read32(MSDC_INTEN); \ + sdr_clr_bits(MSDC_INTEN, val); \ + } while(0) + +#define msdc_irq_restore(val) \ + do { \ + sdr_set_bits(MSDC_INTEN, val); \ + } while(0) + +/* clock source for host: global */ +#if defined (CONFIG_SOC_MT7620) +static u32 hclks[] = {48000000}; /* +/- by chhung */ +#elif defined (CONFIG_SOC_MT7621) +static u32 hclks[] = {50000000}; /* +/- by chhung */ +#endif + +//============================================ +// the power for msdc host controller: global +// always keep the VMC on. +//============================================ +#define msdc_vcore_on(host) \ + do { \ + INIT_MSG("[+]VMC ref. count<%d>", ++host->pwr_ref); \ + (void)hwPowerOn(MT65XX_POWER_LDO_VMC, VOL_3300, "SD"); \ + } while (0) +#define msdc_vcore_off(host) \ + do { \ + INIT_MSG("[-]VMC ref. count<%d>", --host->pwr_ref); \ + (void)hwPowerDown(MT65XX_POWER_LDO_VMC, "SD"); \ + } while (0) + +//==================================== +// the vdd output for card: global +// always keep the VMCH on. +//==================================== +#define msdc_vdd_on(host) \ + do { \ + (void)hwPowerOn(MT65XX_POWER_LDO_VMCH, VOL_3300, "SD"); \ + } while (0) +#define msdc_vdd_off(host) \ + do { \ + (void)hwPowerDown(MT65XX_POWER_LDO_VMCH, "SD"); \ + } while (0) + +#define sdc_is_busy() (sdr_read32(SDC_STS) & SDC_STS_SDCBUSY) +#define sdc_is_cmd_busy() (sdr_read32(SDC_STS) & SDC_STS_CMDBUSY) + +#define sdc_send_cmd(cmd,arg) \ + do { \ + sdr_write32(SDC_ARG, (arg)); \ + sdr_write32(SDC_CMD, (cmd)); \ + } while(0) + +// can modify to read h/w register. +//#define is_card_present(h) ((sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1); +#define is_card_present(h) (((struct msdc_host*)(h))->card_inserted) + +/* +++ by chhung */ +#ifndef __ASSEMBLY__ +#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff) +#else +#define PHYSADDR(a) ((a) & 0x1fffffff) +#endif +/* end of +++ */ +static unsigned int msdc_do_command(struct msdc_host *host, + struct mmc_command *cmd, + int tune, + unsigned long timeout); + +static int msdc_tune_cmdrsp(struct msdc_host*host,struct mmc_command *cmd); + +#ifdef MT6575_SD_DEBUG +static void msdc_dump_card_status(struct msdc_host *host, u32 status) +{ +/* N_MSG is currently a no-op */ +#if 0 + static char *state[] = { + "Idle", /* 0 */ + "Ready", /* 1 */ + "Ident", /* 2 */ + "Stby", /* 3 */ + "Tran", /* 4 */ + "Data", /* 5 */ + "Rcv", /* 6 */ + "Prg", /* 7 */ + "Dis", /* 8 */ + "Reserved", /* 9 */ + "Reserved", /* 10 */ + "Reserved", /* 11 */ + "Reserved", /* 12 */ + "Reserved", /* 13 */ + "Reserved", /* 14 */ + "I/O mode", /* 15 */ + }; +#endif + if (status & R1_OUT_OF_RANGE) + N_MSG(RSP, "[CARD_STATUS] Out of Range"); + if (status & R1_ADDRESS_ERROR) + N_MSG(RSP, "[CARD_STATUS] Address Error"); + if (status & R1_BLOCK_LEN_ERROR) + N_MSG(RSP, "[CARD_STATUS] Block Len Error"); + if (status & R1_ERASE_SEQ_ERROR) + N_MSG(RSP, "[CARD_STATUS] Erase Seq Error"); + if (status & R1_ERASE_PARAM) + N_MSG(RSP, "[CARD_STATUS] Erase Param"); + if (status & R1_WP_VIOLATION) + N_MSG(RSP, "[CARD_STATUS] WP Violation"); + if (status & R1_CARD_IS_LOCKED) + N_MSG(RSP, "[CARD_STATUS] Card is Locked"); + if (status & R1_LOCK_UNLOCK_FAILED) + N_MSG(RSP, "[CARD_STATUS] Lock/Unlock Failed"); + if (status & R1_COM_CRC_ERROR) + N_MSG(RSP, "[CARD_STATUS] Command CRC Error"); + if (status & R1_ILLEGAL_COMMAND) + N_MSG(RSP, "[CARD_STATUS] Illegal Command"); + if (status & R1_CARD_ECC_FAILED) + N_MSG(RSP, "[CARD_STATUS] Card ECC Failed"); + if (status & R1_CC_ERROR) + N_MSG(RSP, "[CARD_STATUS] CC Error"); + if (status & R1_ERROR) + N_MSG(RSP, "[CARD_STATUS] Error"); + if (status & R1_UNDERRUN) + N_MSG(RSP, "[CARD_STATUS] Underrun"); + if (status & R1_OVERRUN) + N_MSG(RSP, "[CARD_STATUS] Overrun"); + if (status & R1_CID_CSD_OVERWRITE) + N_MSG(RSP, "[CARD_STATUS] CID/CSD Overwrite"); + if (status & R1_WP_ERASE_SKIP) + N_MSG(RSP, "[CARD_STATUS] WP Eraser Skip"); + if (status & R1_CARD_ECC_DISABLED) + N_MSG(RSP, "[CARD_STATUS] Card ECC Disabled"); + if (status & R1_ERASE_RESET) + N_MSG(RSP, "[CARD_STATUS] Erase Reset"); + if (status & R1_READY_FOR_DATA) + N_MSG(RSP, "[CARD_STATUS] Ready for Data"); + if (status & R1_SWITCH_ERROR) + N_MSG(RSP, "[CARD_STATUS] Switch error"); + if (status & R1_APP_CMD) + N_MSG(RSP, "[CARD_STATUS] App Command"); + + N_MSG(RSP, "[CARD_STATUS] '%s' State", state[R1_CURRENT_STATE(status)]); +} + +static void msdc_dump_ocr_reg(struct msdc_host *host, u32 resp) +{ + if (resp & (1 << 7)) + N_MSG(RSP, "[OCR] Low Voltage Range"); + if (resp & (1 << 15)) + N_MSG(RSP, "[OCR] 2.7-2.8 volt"); + if (resp & (1 << 16)) + N_MSG(RSP, "[OCR] 2.8-2.9 volt"); + if (resp & (1 << 17)) + N_MSG(RSP, "[OCR] 2.9-3.0 volt"); + if (resp & (1 << 18)) + N_MSG(RSP, "[OCR] 3.0-3.1 volt"); + if (resp & (1 << 19)) + N_MSG(RSP, "[OCR] 3.1-3.2 volt"); + if (resp & (1 << 20)) + N_MSG(RSP, "[OCR] 3.2-3.3 volt"); + if (resp & (1 << 21)) + N_MSG(RSP, "[OCR] 3.3-3.4 volt"); + if (resp & (1 << 22)) + N_MSG(RSP, "[OCR] 3.4-3.5 volt"); + if (resp & (1 << 23)) + N_MSG(RSP, "[OCR] 3.5-3.6 volt"); + if (resp & (1 << 24)) + N_MSG(RSP, "[OCR] Switching to 1.8V Accepted (S18A)"); + if (resp & (1 << 30)) + N_MSG(RSP, "[OCR] Card Capacity Status (CCS)"); + if (resp & (1 << 31)) + N_MSG(RSP, "[OCR] Card Power Up Status (Idle)"); + else + N_MSG(RSP, "[OCR] Card Power Up Status (Busy)"); +} + +static void msdc_dump_rca_resp(struct msdc_host *host, u32 resp) +{ + u32 status = (((resp >> 15) & 0x1) << 23) | + (((resp >> 14) & 0x1) << 22) | + (((resp >> 13) & 0x1) << 19) | + (resp & 0x1fff); + + N_MSG(RSP, "[RCA] 0x%.4x", resp >> 16); + msdc_dump_card_status(host, status); +} + +static void msdc_dump_io_resp(struct msdc_host *host, u32 resp) +{ + u32 flags = (resp >> 8) & 0xFF; +#if 0 + char *state[] = {"DIS", "CMD", "TRN", "RFU"}; +#endif + if (flags & (1 << 7)) + N_MSG(RSP, "[IO] COM_CRC_ERR"); + if (flags & (1 << 6)) + N_MSG(RSP, "[IO] Illgal command"); + if (flags & (1 << 3)) + N_MSG(RSP, "[IO] Error"); + if (flags & (1 << 2)) + N_MSG(RSP, "[IO] RFU"); + if (flags & (1 << 1)) + N_MSG(RSP, "[IO] Function number error"); + if (flags & (1 << 0)) + N_MSG(RSP, "[IO] Out of range"); + + N_MSG(RSP, "[IO] State: %s, Data:0x%x", state[(resp >> 12) & 0x3], resp & 0xFF); +} +#endif + +static void msdc_set_timeout(struct msdc_host *host, u32 ns, u32 clks) +{ + u32 base = host->base; + u32 timeout, clk_ns; + + host->timeout_ns = ns; + host->timeout_clks = clks; + + clk_ns = 1000000000UL / host->sclk; + timeout = ns / clk_ns + clks; + timeout = timeout >> 16; /* in 65536 sclk cycle unit */ + timeout = timeout > 1 ? timeout - 1 : 0; + timeout = timeout > 255 ? 255 : timeout; + + sdr_set_field(SDC_CFG, SDC_CFG_DTOC, timeout); + + N_MSG(OPS, "Set read data timeout: %dns %dclks -> %d x 65536 cycles", + ns, clks, timeout + 1); +} + +/* msdc_eirq_sdio() will be called when EIRQ(for WIFI) */ +static void msdc_eirq_sdio(void *data) +{ + struct msdc_host *host = (struct msdc_host *)data; + + N_MSG(INT, "SDIO EINT"); + + mmc_signal_sdio_irq(host->mmc); +} + +/* msdc_eirq_cd will not be used! We not using EINT for card detection. */ +static void msdc_eirq_cd(void *data) +{ + struct msdc_host *host = (struct msdc_host *)data; + + N_MSG(INT, "CD EINT"); + +#if 0 + tasklet_hi_schedule(&host->card_tasklet); +#else + schedule_delayed_work(&host->card_delaywork, HZ); +#endif +} + +#if 0 +static void msdc_tasklet_card(unsigned long arg) +{ + struct msdc_host *host = (struct msdc_host *)arg; +#else +static void msdc_tasklet_card(struct work_struct *work) +{ + struct msdc_host *host = (struct msdc_host *)container_of(work, + struct msdc_host, card_delaywork.work); +#endif + struct msdc_hw *hw = host->hw; + u32 base = host->base; + u32 inserted; + u32 status = 0; + //u32 change = 0; + + spin_lock(&host->lock); + + if (hw->get_cd_status) { // NULL + inserted = hw->get_cd_status(); + } else { + status = sdr_read32(MSDC_PS); + if (cd_active_low) + inserted = (status & MSDC_PS_CDSTS) ? 0 : 1; + else + inserted = (status & MSDC_PS_CDSTS) ? 1 : 0; + } + +#if 0 + change = host->card_inserted ^ inserted; + host->card_inserted = inserted; + + if (change && !host->suspend) { + if (inserted) { + host->mmc->f_max = HOST_MAX_MCLK; // work around + } + mmc_detect_change(host->mmc, msecs_to_jiffies(20)); + } +#else /* Make sure: handle the last interrupt */ + host->card_inserted = inserted; + + if (!host->suspend) { + host->mmc->f_max = HOST_MAX_MCLK; + mmc_detect_change(host->mmc, msecs_to_jiffies(20)); + } + + IRQ_MSG("card found<%s>", inserted ? "inserted" : "removed"); +#endif + + spin_unlock(&host->lock); +} + +#if 0 /* --- by chhung */ +/* For E2 only */ +static u8 clk_src_bit[4] = { + 0, 3, 5, 7 +}; + +static void msdc_select_clksrc(struct msdc_host* host, unsigned char clksrc) +{ + u32 val; + u32 base = host->base; + + BUG_ON(clksrc > 3); + INIT_MSG("set clock source to <%d>", clksrc); + + val = sdr_read32(MSDC_CLKSRC_REG); + if (sdr_read32(MSDC_ECO_VER) >= 4) { + val &= ~(0x3 << clk_src_bit[host->id]); + val |= clksrc << clk_src_bit[host->id]; + } else { + val &= ~0x3; val |= clksrc; + } + sdr_write32(MSDC_CLKSRC_REG, val); + + host->hclk = hclks[clksrc]; + host->hw->clk_src = clksrc; +} +#endif /* end of --- */ + +static void msdc_set_mclk(struct msdc_host *host, int ddr, unsigned int hz) +{ + //struct msdc_hw *hw = host->hw; + u32 base = host->base; + u32 mode; + u32 flags; + u32 div; + u32 sclk; + u32 hclk = host->hclk; + //u8 clksrc = hw->clk_src; + + if (!hz) { // set mmc system clock to 0 ? + //ERR_MSG("set mclk to 0!!!"); + msdc_reset(); + return; + } + + msdc_irq_save(flags); + +#if defined (CONFIG_MT7621_FPGA) || defined (CONFIG_MT7628_FPGA) + mode = 0x0; /* use divisor */ + if (hz >= (hclk >> 1)) { + div = 0; /* mean div = 1/2 */ + sclk = hclk >> 1; /* sclk = clk / 2 */ + } else { + div = (hclk + ((hz << 2) - 1)) / (hz << 2); + sclk = (hclk >> 2) / div; + } +#else + if (ddr) { + mode = 0x2; /* ddr mode and use divisor */ + if (hz >= (hclk >> 2)) { + div = 1; /* mean div = 1/4 */ + sclk = hclk >> 2; /* sclk = clk / 4 */ + } else { + div = (hclk + ((hz << 2) - 1)) / (hz << 2); + sclk = (hclk >> 2) / div; + } + } else if (hz >= hclk) { /* bug fix */ + mode = 0x1; /* no divisor and divisor is ignored */ + div = 0; + sclk = hclk; + } else { + mode = 0x0; /* use divisor */ + if (hz >= (hclk >> 1)) { + div = 0; /* mean div = 1/2 */ + sclk = hclk >> 1; /* sclk = clk / 2 */ + } else { + div = (hclk + ((hz << 2) - 1)) / (hz << 2); + sclk = (hclk >> 2) / div; + } + } +#endif + /* set clock mode and divisor */ + sdr_set_field(MSDC_CFG, MSDC_CFG_CKMOD, mode); + sdr_set_field(MSDC_CFG, MSDC_CFG_CKDIV, div); + + /* wait clock stable */ + while (!(sdr_read32(MSDC_CFG) & MSDC_CFG_CKSTB)); + + host->sclk = sclk; + host->mclk = hz; + msdc_set_timeout(host, host->timeout_ns, host->timeout_clks); // need? + + INIT_MSG("================"); + INIT_MSG("!!! Set<%dKHz> Source<%dKHz> -> sclk<%dKHz>", hz/1000, hclk/1000, sclk/1000); + INIT_MSG("================"); + + msdc_irq_restore(flags); +} + +/* Fix me. when need to abort */ +static void msdc_abort_data(struct msdc_host *host) +{ + u32 base = host->base; + struct mmc_command *stop = host->mrq->stop; + + ERR_MSG("Need to Abort. dma<%d>", host->dma_xfer); + + msdc_reset(); + msdc_clr_fifo(); + msdc_clr_int(); + + // need to check FIFO count 0 ? + + if (stop) { /* try to stop, but may not success */ + ERR_MSG("stop when abort CMD<%d>", stop->opcode); + (void)msdc_do_command(host, stop, 0, CMD_TIMEOUT); + } + + //if (host->mclk >= 25000000) { + // msdc_set_mclk(host, 0, host->mclk >> 1); + //} +} + +#if 0 /* --- by chhung */ +static void msdc_pin_config(struct msdc_host *host, int mode) +{ + struct msdc_hw *hw = host->hw; + u32 base = host->base; + int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN; + + /* Config WP pin */ + if (hw->flags & MSDC_WP_PIN_EN) { + if (hw->config_gpio_pin) /* NULL */ + hw->config_gpio_pin(MSDC_WP_PIN, pull); + } + + switch (mode) { + case MSDC_PIN_PULL_UP: + //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 1); /* Check & FIXME */ + //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */ + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 1); + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 1); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0); + break; + case MSDC_PIN_PULL_DOWN: + //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */ + //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 1); /* Check & FIXME */ + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0); + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 1); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 1); + break; + case MSDC_PIN_PULL_NONE: + default: + //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPU, 0); /* Check & FIXME */ + //sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKPD, 0); /* Check & FIXME */ + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPU, 0); + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDPD, 0); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPU, 0); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATPD, 0); + break; + } + + N_MSG(CFG, "Pins mode(%d), down(%d), up(%d)", + mode, MSDC_PIN_PULL_DOWN, MSDC_PIN_PULL_UP); +} + +void msdc_pin_reset(struct msdc_host *host, int mode) +{ + struct msdc_hw *hw = (struct msdc_hw *)host->hw; + u32 base = host->base; + int pull = (mode == MSDC_PIN_PULL_UP) ? GPIO_PULL_UP : GPIO_PULL_DOWN; + + /* Config reset pin */ + if (hw->flags & MSDC_RST_PIN_EN) { + if (hw->config_gpio_pin) /* NULL */ + hw->config_gpio_pin(MSDC_RST_PIN, pull); + + if (mode == MSDC_PIN_PULL_UP) { + sdr_clr_bits(EMMC_IOCON, EMMC_IOCON_BOOTRST); + } else { + sdr_set_bits(EMMC_IOCON, EMMC_IOCON_BOOTRST); + } + } +} + +static void msdc_core_power(struct msdc_host *host, int on) +{ + N_MSG(CFG, "Turn %s %s power (copower: %d -> %d)", + on ? "on" : "off", "core", host->core_power, on); + + if (on && host->core_power == 0) { + msdc_vcore_on(host); + host->core_power = 1; + msleep(1); + } else if (!on && host->core_power == 1) { + msdc_vcore_off(host); + host->core_power = 0; + msleep(1); + } +} + +static void msdc_host_power(struct msdc_host *host, int on) +{ + N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "host"); + + if (on) { + //msdc_core_power(host, 1); // need do card detection. + msdc_pin_reset(host, MSDC_PIN_PULL_UP); + } else { + msdc_pin_reset(host, MSDC_PIN_PULL_DOWN); + //msdc_core_power(host, 0); + } +} + +static void msdc_card_power(struct msdc_host *host, int on) +{ + N_MSG(CFG, "Turn %s %s power ", on ? "on" : "off", "card"); + + if (on) { + msdc_pin_config(host, MSDC_PIN_PULL_UP); + if (host->hw->ext_power_on) { + host->hw->ext_power_on(); + } else { + //msdc_vdd_on(host); // need todo card detection. + } + msleep(1); + } else { + if (host->hw->ext_power_off) { + host->hw->ext_power_off(); + } else { + //msdc_vdd_off(host); + } + msdc_pin_config(host, MSDC_PIN_PULL_DOWN); + msleep(1); + } +} + +static void msdc_set_power_mode(struct msdc_host *host, u8 mode) +{ + N_MSG(CFG, "Set power mode(%d)", mode); + + if (host->power_mode == MMC_POWER_OFF && mode != MMC_POWER_OFF) { + msdc_host_power(host, 1); + msdc_card_power(host, 1); + } else if (host->power_mode != MMC_POWER_OFF && mode == MMC_POWER_OFF) { + msdc_card_power(host, 0); + msdc_host_power(host, 0); + } + host->power_mode = mode; +} +#endif /* end of --- */ + +#ifdef CONFIG_PM +/* + register as callback function of WIFI(combo_sdio_register_pm) . + can called by msdc_drv_suspend/resume too. +*/ +static void msdc_pm(pm_message_t state, void *data) +{ + struct msdc_host *host = (struct msdc_host *)data; + int evt = state.event; + + if (evt == PM_EVENT_USER_RESUME || evt == PM_EVENT_USER_SUSPEND) { + INIT_MSG("USR_%s: suspend<%d> power<%d>", + evt == PM_EVENT_USER_RESUME ? "EVENT_USER_RESUME" : "EVENT_USER_SUSPEND", + host->suspend, host->power_mode); + } + + if (evt == PM_EVENT_SUSPEND || evt == PM_EVENT_USER_SUSPEND) { + if (host->suspend) /* already suspend */ /* default 0*/ + return; + + /* for memory card. already power off by mmc */ + if (evt == PM_EVENT_SUSPEND && host->power_mode == MMC_POWER_OFF) + return; + + host->suspend = 1; + host->pm_state = state; /* default PMSG_RESUME */ + + INIT_MSG("%s Suspend", evt == PM_EVENT_SUSPEND ? "PM" : "USR"); + if(host->hw->flags & MSDC_SYS_SUSPEND) /* set for card */ + (void)mmc_suspend_host(host->mmc); + else { + // host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* just for double confirm */ /* --- by chhung */ + mmc_remove_host(host->mmc); + } + } else if (evt == PM_EVENT_RESUME || evt == PM_EVENT_USER_RESUME) { + if (!host->suspend){ + //ERR_MSG("warning: already resume"); + return; + } + + /* No PM resume when USR suspend */ + if (evt == PM_EVENT_RESUME && host->pm_state.event == PM_EVENT_USER_SUSPEND) { + ERR_MSG("PM Resume when in USR Suspend"); /* won't happen. */ + return; + } + + host->suspend = 0; + host->pm_state = state; + + INIT_MSG("%s Resume", evt == PM_EVENT_RESUME ? "PM" : "USR"); + if(host->hw->flags & MSDC_SYS_SUSPEND) { /* will not set for WIFI */ + (void)mmc_resume_host(host->mmc); + } + else { + // host->mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* --- by chhung */ + mmc_add_host(host->mmc); + } + } +} +#endif + +/*--------------------------------------------------------------------------*/ +/* mmc_host_ops members */ +/*--------------------------------------------------------------------------*/ +static unsigned int msdc_command_start(struct msdc_host *host, + struct mmc_command *cmd, + int tune, /* not used */ + unsigned long timeout) +{ + u32 base = host->base; + u32 opcode = cmd->opcode; + u32 rawcmd; + u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | + MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | + MSDC_INT_ACMD19_DONE; + + u32 resp; + unsigned long tmo; + + /* Protocol layer does not provide response type, but our hardware needs + * to know exact type, not just size! + */ + if (opcode == MMC_SEND_OP_COND || opcode == SD_APP_OP_COND) + resp = RESP_R3; + else if (opcode == MMC_SET_RELATIVE_ADDR || opcode == SD_SEND_RELATIVE_ADDR) + resp = (mmc_cmd_type(cmd) == MMC_CMD_BCR) ? RESP_R6 : RESP_R1; + else if (opcode == MMC_FAST_IO) + resp = RESP_R4; + else if (opcode == MMC_GO_IRQ_STATE) + resp = RESP_R5; + else if (opcode == MMC_SELECT_CARD) + resp = (cmd->arg != 0) ? RESP_R1B : RESP_NONE; + else if (opcode == SD_IO_RW_DIRECT || opcode == SD_IO_RW_EXTENDED) + resp = RESP_R1; /* SDIO workaround. */ + else if (opcode == SD_SEND_IF_COND && (mmc_cmd_type(cmd) == MMC_CMD_BCR)) + resp = RESP_R1; + else { + switch (mmc_resp_type(cmd)) { + case MMC_RSP_R1: + resp = RESP_R1; + break; + case MMC_RSP_R1B: + resp = RESP_R1B; + break; + case MMC_RSP_R2: + resp = RESP_R2; + break; + case MMC_RSP_R3: + resp = RESP_R3; + break; + case MMC_RSP_NONE: + default: + resp = RESP_NONE; + break; + } + } + + cmd->error = 0; + /* rawcmd : + * vol_swt << 30 | auto_cmd << 28 | blklen << 16 | go_irq << 15 | + * stop << 14 | rw << 13 | dtype << 11 | rsptyp << 7 | brk << 6 | opcode + */ + rawcmd = opcode | msdc_rsp[resp] << 7 | host->blksz << 16; + + if (opcode == MMC_READ_MULTIPLE_BLOCK) { + rawcmd |= (2 << 11); + } else if (opcode == MMC_READ_SINGLE_BLOCK) { + rawcmd |= (1 << 11); + } else if (opcode == MMC_WRITE_MULTIPLE_BLOCK) { + rawcmd |= ((2 << 11) | (1 << 13)); + } else if (opcode == MMC_WRITE_BLOCK) { + rawcmd |= ((1 << 11) | (1 << 13)); + } else if (opcode == SD_IO_RW_EXTENDED) { + if (cmd->data->flags & MMC_DATA_WRITE) + rawcmd |= (1 << 13); + if (cmd->data->blocks > 1) + rawcmd |= (2 << 11); + else + rawcmd |= (1 << 11); + } else if (opcode == SD_IO_RW_DIRECT && cmd->flags == (unsigned int)-1) { + rawcmd |= (1 << 14); + } else if ((opcode == SD_APP_SEND_SCR) || + (opcode == SD_APP_SEND_NUM_WR_BLKS) || + (opcode == SD_SWITCH && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) || + (opcode == SD_APP_SD_STATUS && (mmc_cmd_type(cmd) == MMC_CMD_ADTC)) || + (opcode == MMC_SEND_EXT_CSD && (mmc_cmd_type(cmd) == MMC_CMD_ADTC))) { + rawcmd |= (1 << 11); + } else if (opcode == MMC_STOP_TRANSMISSION) { + rawcmd |= (1 << 14); + rawcmd &= ~(0x0FFF << 16); + } + + N_MSG(CMD, "CMD<%d><0x%.8x> Arg<0x%.8x>", opcode , rawcmd, cmd->arg); + + tmo = jiffies + timeout; + + if (opcode == MMC_SEND_STATUS) { + for (;;) { + if (!sdc_is_cmd_busy()) + break; + + if (time_after(jiffies, tmo)) { + ERR_MSG("XXX cmd_busy timeout: before CMD<%d>", opcode); + cmd->error = (unsigned int)-ETIMEDOUT; + msdc_reset(); + goto end; + } + } + }else { + for (;;) { + if (!sdc_is_busy()) + break; + if (time_after(jiffies, tmo)) { + ERR_MSG("XXX sdc_busy timeout: before CMD<%d>", opcode); + cmd->error = (unsigned int)-ETIMEDOUT; + msdc_reset(); + goto end; + } + } + } + + //BUG_ON(in_interrupt()); + host->cmd = cmd; + host->cmd_rsp = resp; + + init_completion(&host->cmd_done); + + sdr_set_bits(MSDC_INTEN, wints); + sdc_send_cmd(rawcmd, cmd->arg); + +end: + return cmd->error; +} + +static unsigned int msdc_command_resp(struct msdc_host *host, + struct mmc_command *cmd, + int tune, + unsigned long timeout) +{ + u32 base = host->base; + u32 opcode = cmd->opcode; + //u32 rawcmd; + u32 resp; + u32 wints = MSDC_INT_CMDRDY | MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | + MSDC_INT_ACMDRDY | MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | + MSDC_INT_ACMD19_DONE; + + resp = host->cmd_rsp; + + BUG_ON(in_interrupt()); + //init_completion(&host->cmd_done); + //sdr_set_bits(MSDC_INTEN, wints); + + spin_unlock(&host->lock); + if(!wait_for_completion_timeout(&host->cmd_done, 10*timeout)){ + ERR_MSG("XXX CMD<%d> wait_for_completion timeout ARG<0x%.8x>", opcode, cmd->arg); + cmd->error = (unsigned int)-ETIMEDOUT; + msdc_reset(); + } + spin_lock(&host->lock); + + sdr_clr_bits(MSDC_INTEN, wints); + host->cmd = NULL; + +//end: +#ifdef MT6575_SD_DEBUG + switch (resp) { + case RESP_NONE: + N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)", opcode, cmd->error, resp); + break; + case RESP_R2: + N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= %.8x %.8x %.8x %.8x", + opcode, cmd->error, resp, cmd->resp[0], cmd->resp[1], + cmd->resp[2], cmd->resp[3]); + break; + default: /* Response types 1, 3, 4, 5, 6, 7(1b) */ + N_MSG(RSP, "CMD_RSP(%d): %d RSP(%d)= 0x%.8x", + opcode, cmd->error, resp, cmd->resp[0]); + if (cmd->error == 0) { + switch (resp) { + case RESP_R1: + case RESP_R1B: + msdc_dump_card_status(host, cmd->resp[0]); + break; + case RESP_R3: + msdc_dump_ocr_reg(host, cmd->resp[0]); + break; + case RESP_R5: + msdc_dump_io_resp(host, cmd->resp[0]); + break; + case RESP_R6: + msdc_dump_rca_resp(host, cmd->resp[0]); + break; + } + } + break; + } +#endif + + /* do we need to save card's RCA when SD_SEND_RELATIVE_ADDR */ + + if (!tune) { + return cmd->error; + } + + /* memory card CRC */ + if(host->hw->flags & MSDC_REMOVABLE && cmd->error == (unsigned int)(-EIO) ) { + if (sdr_read32(SDC_CMD) & 0x1800) { /* check if has data phase */ + msdc_abort_data(host); + } else { + /* do basic: reset*/ + msdc_reset(); + msdc_clr_fifo(); + msdc_clr_int(); + } + cmd->error = msdc_tune_cmdrsp(host,cmd); + } + + // check DAT0 + /* if (resp == RESP_R1B) { + while ((sdr_read32(MSDC_PS) & 0x10000) != 0x10000); + } */ + /* CMD12 Error Handle */ + + return cmd->error; +} + +static unsigned int msdc_do_command(struct msdc_host *host, + struct mmc_command *cmd, + int tune, + unsigned long timeout) +{ + if (msdc_command_start(host, cmd, tune, timeout)) + goto end; + + if (msdc_command_resp(host, cmd, tune, timeout)) + goto end; + +end: + + N_MSG(CMD, " return<%d> resp<0x%.8x>", cmd->error, cmd->resp[0]); + return cmd->error; +} + +/* The abort condition when PIO read/write + tmo: +*/ +static int msdc_pio_abort(struct msdc_host *host, struct mmc_data *data, unsigned long tmo) +{ + int ret = 0; + u32 base = host->base; + + if (atomic_read(&host->abort)) { + ret = 1; + } + + if (time_after(jiffies, tmo)) { + data->error = (unsigned int)-ETIMEDOUT; + ERR_MSG("XXX PIO Data Timeout: CMD<%d>", host->mrq->cmd->opcode); + ret = 1; + } + + if(ret) { + msdc_reset(); + msdc_clr_fifo(); + msdc_clr_int(); + ERR_MSG("msdc pio find abort"); + } + return ret; +} + +/* + Need to add a timeout, or WDT timeout, system reboot. +*/ +// pio mode data read/write +static int msdc_pio_read(struct msdc_host *host, struct mmc_data *data) +{ + struct scatterlist *sg = data->sg; + u32 base = host->base; + u32 num = data->sg_len; + u32 *ptr; + u8 *u8ptr; + u32 left = 0; + u32 count, size = 0; + u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; + unsigned long tmo = jiffies + DAT_TIMEOUT; + + sdr_set_bits(MSDC_INTEN, wints); + while (num) { + left = sg_dma_len(sg); + ptr = sg_virt(sg); + while (left) { + if ((left >= MSDC_FIFO_THD) && (msdc_rxfifocnt() >= MSDC_FIFO_THD)) { + count = MSDC_FIFO_THD >> 2; + do { + *ptr++ = msdc_fifo_read32(); + } while (--count); + left -= MSDC_FIFO_THD; + } else if ((left < MSDC_FIFO_THD) && msdc_rxfifocnt() >= left) { + while (left > 3) { + *ptr++ = msdc_fifo_read32(); + left -= 4; + } + + u8ptr = (u8 *)ptr; + while(left) { + * u8ptr++ = msdc_fifo_read8(); + left--; + } + } + + if (msdc_pio_abort(host, data, tmo)) { + goto end; + } + } + size += sg_dma_len(sg); + sg = sg_next(sg); num--; + } +end: + data->bytes_xfered += size; + N_MSG(FIO, " PIO Read<%d>bytes", size); + + sdr_clr_bits(MSDC_INTEN, wints); + if(data->error) ERR_MSG("read pio data->error<%d> left<%d> size<%d>", data->error, left, size); + return data->error; +} + +/* please make sure won't using PIO when size >= 512 + which means, memory card block read/write won't using pio + then don't need to handle the CMD12 when data error. +*/ +static int msdc_pio_write(struct msdc_host* host, struct mmc_data *data) +{ + u32 base = host->base; + struct scatterlist *sg = data->sg; + u32 num = data->sg_len; + u32 *ptr; + u8 *u8ptr; + u32 left; + u32 count, size = 0; + u32 wints = MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; + unsigned long tmo = jiffies + DAT_TIMEOUT; + + sdr_set_bits(MSDC_INTEN, wints); + while (num) { + left = sg_dma_len(sg); + ptr = sg_virt(sg); + + while (left) { + if (left >= MSDC_FIFO_SZ && msdc_txfifocnt() == 0) { + count = MSDC_FIFO_SZ >> 2; + do { + msdc_fifo_write32(*ptr); ptr++; + } while (--count); + left -= MSDC_FIFO_SZ; + } else if (left < MSDC_FIFO_SZ && msdc_txfifocnt() == 0) { + while (left > 3) { + msdc_fifo_write32(*ptr); ptr++; + left -= 4; + } + + u8ptr = (u8*)ptr; + while(left){ + msdc_fifo_write8(*u8ptr); u8ptr++; + left--; + } + } + + if (msdc_pio_abort(host, data, tmo)) { + goto end; + } + } + size += sg_dma_len(sg); + sg = sg_next(sg); num--; + } +end: + data->bytes_xfered += size; + N_MSG(FIO, " PIO Write<%d>bytes", size); + if(data->error) ERR_MSG("write pio data->error<%d>", data->error); + + sdr_clr_bits(MSDC_INTEN, wints); + return data->error; +} + +#if 0 /* --- by chhung */ +// DMA resume / start / stop +static void msdc_dma_resume(struct msdc_host *host) +{ + u32 base = host->base; + + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_RESUME, 1); + + N_MSG(DMA, "DMA resume"); +} +#endif /* end of --- */ + +static void msdc_dma_start(struct msdc_host *host) +{ + u32 base = host->base; + u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; + + sdr_set_bits(MSDC_INTEN, wints); + //dsb(); /* --- by chhung */ + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_START, 1); + + N_MSG(DMA, "DMA start"); +} + +static void msdc_dma_stop(struct msdc_host *host) +{ + u32 base = host->base; + //u32 retries=500; + u32 wints = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO | MSDC_INTEN_DATCRCERR ; + + N_MSG(DMA, "DMA status: 0x%.8x",sdr_read32(MSDC_DMA_CFG)); + //while (sdr_read32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS); + + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_STOP, 1); + while (sdr_read32(MSDC_DMA_CFG) & MSDC_DMA_CFG_STS); + + //dsb(); /* --- by chhung */ + sdr_clr_bits(MSDC_INTEN, wints); /* Not just xfer_comp */ + + N_MSG(DMA, "DMA stop"); +} + +#if 0 /* --- by chhung */ +/* dump a gpd list */ +static void msdc_dma_dump(struct msdc_host *host, struct msdc_dma *dma) +{ + gpd_t *gpd = dma->gpd; + bd_t *bd = dma->bd; + bd_t *ptr; + int i = 0; + int p_to_v; + + if (dma->mode != MSDC_MODE_DMA_DESC) { + return; + } + + ERR_MSG("try to dump gpd and bd"); + + /* dump gpd */ + ERR_MSG(".gpd<0x%.8x> gpd_phy<0x%.8x>", (int)gpd, (int)dma->gpd_addr); + ERR_MSG("...hwo <%d>", gpd->hwo ); + ERR_MSG("...bdp <%d>", gpd->bdp ); + ERR_MSG("...chksum<0x%.8x>", gpd->chksum ); + //ERR_MSG("...intr <0x%.8x>", gpd->intr ); + ERR_MSG("...next <0x%.8x>", (int)gpd->next ); + ERR_MSG("...ptr <0x%.8x>", (int)gpd->ptr ); + ERR_MSG("...buflen<0x%.8x>", gpd->buflen ); + //ERR_MSG("...extlen<0x%.8x>", gpd->extlen ); + //ERR_MSG("...arg <0x%.8x>", gpd->arg ); + //ERR_MSG("...blknum<0x%.8x>", gpd->blknum ); + //ERR_MSG("...cmd <0x%.8x>", gpd->cmd ); + + /* dump bd */ + ERR_MSG(".bd<0x%.8x> bd_phy<0x%.8x> gpd_ptr<0x%.8x>", (int)bd, (int)dma->bd_addr, (int)gpd->ptr); + ptr = bd; + p_to_v = ((u32)bd - (u32)dma->bd_addr); + while (1) { + ERR_MSG(".bd[%d]", i); i++; + ERR_MSG("...eol <%d>", ptr->eol ); + ERR_MSG("...chksum<0x%.8x>", ptr->chksum ); + //ERR_MSG("...blkpad<0x%.8x>", ptr->blkpad ); + //ERR_MSG("...dwpad <0x%.8x>", ptr->dwpad ); + ERR_MSG("...next <0x%.8x>", (int)ptr->next ); + ERR_MSG("...ptr <0x%.8x>", (int)ptr->ptr ); + ERR_MSG("...buflen<0x%.8x>", (int)ptr->buflen ); + + if (ptr->eol == 1) { + break; + } + + /* find the next bd, virtual address of ptr->next */ + /* don't need to enable when use malloc */ + //BUG_ON( (ptr->next + p_to_v)!=(ptr+1) ); + //ERR_MSG(".next bd<0x%.8x><0x%.8x>", (ptr->next + p_to_v), (ptr+1)); + ptr++; + } + + ERR_MSG("dump gpd and bd finished"); +} +#endif /* end of --- */ + +/* calc checksum */ +static u8 msdc_dma_calcs(u8 *buf, u32 len) +{ + u32 i, sum = 0; + for (i = 0; i < len; i++) { + sum += buf[i]; + } + return 0xFF - (u8)sum; +} + +/* gpd bd setup + dma registers */ +static int msdc_dma_config(struct msdc_host *host, struct msdc_dma *dma) +{ + u32 base = host->base; + u32 sglen = dma->sglen; + //u32 i, j, num, bdlen, arg, xfersz; + u32 j, num, bdlen; + u8 blkpad, dwpad, chksum; + struct scatterlist *sg = dma->sg; + gpd_t *gpd; + bd_t *bd; + + switch (dma->mode) { + case MSDC_MODE_DMA_BASIC: + BUG_ON(dma->xfersz > 65535); + BUG_ON(dma->sglen != 1); + sdr_write32(MSDC_DMA_SA, PHYSADDR(sg_dma_address(sg))); + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_LASTBUF, 1); +//#if defined (CONFIG_RALINK_MT7620) + if (ralink_soc == MT762X_SOC_MT7620A) + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_XFERSZ, sg_dma_len(sg)); +//#elif defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) + else + sdr_write32((volatile u32*)(RALINK_MSDC_BASE+0xa8), sg_dma_len(sg)); +//#endif + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz); + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 0); + break; + case MSDC_MODE_DMA_DESC: + blkpad = (dma->flags & DMA_FLAG_PAD_BLOCK) ? 1 : 0; + dwpad = (dma->flags & DMA_FLAG_PAD_DWORD) ? 1 : 0; + chksum = (dma->flags & DMA_FLAG_EN_CHKSUM) ? 1 : 0; + + /* calculate the required number of gpd */ + num = (sglen + MAX_BD_PER_GPD - 1) / MAX_BD_PER_GPD; + BUG_ON(num !=1 ); + + gpd = dma->gpd; + bd = dma->bd; + bdlen = sglen; + + /* modify gpd*/ + //gpd->intr = 0; + gpd->hwo = 1; /* hw will clear it */ + gpd->bdp = 1; + gpd->chksum = 0; /* need to clear first. */ + gpd->chksum = (chksum ? msdc_dma_calcs((u8 *)gpd, 16) : 0); + + /* modify bd*/ + for (j = 0; j < bdlen; j++) { + msdc_init_bd(&bd[j], blkpad, dwpad, sg_dma_address(sg), sg_dma_len(sg)); + if(j == bdlen - 1) { + bd[j].eol = 1; /* the last bd */ + } else { + bd[j].eol = 0; + } + bd[j].chksum = 0; /* checksume need to clear first */ + bd[j].chksum = (chksum ? msdc_dma_calcs((u8 *)(&bd[j]), 16) : 0); + sg++; + } + + dma->used_gpd += 2; + dma->used_bd += bdlen; + + sdr_set_field(MSDC_DMA_CFG, MSDC_DMA_CFG_DECSEN, chksum); + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_BRUSTSZ, dma->burstsz); + sdr_set_field(MSDC_DMA_CTRL, MSDC_DMA_CTRL_MODE, 1); + + sdr_write32(MSDC_DMA_SA, PHYSADDR((u32)dma->gpd_addr)); + break; + + default: + break; + } + + N_MSG(DMA, "DMA_CTRL = 0x%x", sdr_read32(MSDC_DMA_CTRL)); + N_MSG(DMA, "DMA_CFG = 0x%x", sdr_read32(MSDC_DMA_CFG)); + N_MSG(DMA, "DMA_SA = 0x%x", sdr_read32(MSDC_DMA_SA)); + + return 0; +} + +static void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, + struct scatterlist *sg, unsigned int sglen) +{ + BUG_ON(sglen > MAX_BD_NUM); /* not support currently */ + + dma->sg = sg; + dma->flags = DMA_FLAG_EN_CHKSUM; + //dma->flags = DMA_FLAG_NONE; /* CHECKME */ + dma->sglen = sglen; + dma->xfersz = host->xfer_size; + dma->burstsz = MSDC_BRUST_64B; + + if (sglen == 1 && sg_dma_len(sg) <= MAX_DMA_CNT) + dma->mode = MSDC_MODE_DMA_BASIC; + else + dma->mode = MSDC_MODE_DMA_DESC; + + N_MSG(DMA, "DMA mode<%d> sglen<%d> xfersz<%d>", dma->mode, dma->sglen, dma->xfersz); + + msdc_dma_config(host, dma); + + /*if (dma->mode == MSDC_MODE_DMA_DESC) { + //msdc_dma_dump(host, dma); + } */ +} + +/* set block number before send command */ +static void msdc_set_blknum(struct msdc_host *host, u32 blknum) +{ + u32 base = host->base; + + sdr_write32(SDC_BLK_NUM, blknum); +} + +static int msdc_do_request(struct mmc_host*mmc, struct mmc_request*mrq) +{ + struct msdc_host *host = mmc_priv(mmc); + struct mmc_command *cmd; + struct mmc_data *data; + u32 base = host->base; + //u32 intsts = 0; + unsigned int left=0; + int dma = 0, read = 1, dir = DMA_FROM_DEVICE, send_type=0; + + #define SND_DAT 0 + #define SND_CMD 1 + + BUG_ON(mmc == NULL); + BUG_ON(mrq == NULL); + + host->error = 0; + atomic_set(&host->abort, 0); + + cmd = mrq->cmd; + data = mrq->cmd->data; + +#if 0 /* --- by chhung */ + //if(host->id ==1){ + N_MSG(OPS, "enable clock!"); + msdc_ungate_clock(host->id); + //} +#endif /* end of --- */ + + if (!data) { + send_type=SND_CMD; + if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) { + goto done; + } + } else { + BUG_ON(data->blksz > HOST_MAX_BLKSZ); + send_type=SND_DAT; + + data->error = 0; + read = data->flags & MMC_DATA_READ ? 1 : 0; + host->data = data; + host->xfer_size = data->blocks * data->blksz; + host->blksz = data->blksz; + + /* deside the transfer mode */ + if (drv_mode[host->id] == MODE_PIO) { + host->dma_xfer = dma = 0; + } else if (drv_mode[host->id] == MODE_DMA) { + host->dma_xfer = dma = 1; + } else if (drv_mode[host->id] == MODE_SIZE_DEP) { + host->dma_xfer = dma = ((host->xfer_size >= dma_size[host->id]) ? 1 : 0); + } + + if (read) { + if ((host->timeout_ns != data->timeout_ns) || + (host->timeout_clks != data->timeout_clks)) { + msdc_set_timeout(host, data->timeout_ns, data->timeout_clks); + } + } + + msdc_set_blknum(host, data->blocks); + //msdc_clr_fifo(); /* no need */ + + if (dma) { + msdc_dma_on(); /* enable DMA mode first!! */ + init_completion(&host->xfer_done); + + /* start the command first*/ + if (msdc_command_start(host, cmd, 1, CMD_TIMEOUT) != 0) + goto done; + + dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + (void)dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, dir); + msdc_dma_setup(host, &host->dma, data->sg, data->sg_len); + + /* then wait command done */ + if (msdc_command_resp(host, cmd, 1, CMD_TIMEOUT) != 0) + goto done; + + /* for read, the data coming too fast, then CRC error + start DMA no business with CRC. */ + //init_completion(&host->xfer_done); + msdc_dma_start(host); + + spin_unlock(&host->lock); + if(!wait_for_completion_timeout(&host->xfer_done, DAT_TIMEOUT)){ + ERR_MSG("XXX CMD<%d> wait xfer_done<%d> timeout!!", cmd->opcode, data->blocks * data->blksz); + ERR_MSG(" DMA_SA = 0x%x", sdr_read32(MSDC_DMA_SA)); + ERR_MSG(" DMA_CA = 0x%x", sdr_read32(MSDC_DMA_CA)); + ERR_MSG(" DMA_CTRL = 0x%x", sdr_read32(MSDC_DMA_CTRL)); + ERR_MSG(" DMA_CFG = 0x%x", sdr_read32(MSDC_DMA_CFG)); + data->error = (unsigned int)-ETIMEDOUT; + + msdc_reset(); + msdc_clr_fifo(); + msdc_clr_int(); + } + spin_lock(&host->lock); + msdc_dma_stop(host); + } else { + /* Firstly: send command */ + if (msdc_do_command(host, cmd, 1, CMD_TIMEOUT) != 0) { + goto done; + } + + /* Secondly: pio data phase */ + if (read) { + if (msdc_pio_read(host, data)){ + goto done; + } + } else { + if (msdc_pio_write(host, data)) { + goto done; + } + } + + /* For write case: make sure contents in fifo flushed to device */ + if (!read) { + while (1) { + left=msdc_txfifocnt(); + if (left == 0) { + break; + } + if (msdc_pio_abort(host, data, jiffies + DAT_TIMEOUT)) { + break; + /* Fix me: what about if data error, when stop ? how to? */ + } + } + } else { + /* Fix me: read case: need to check CRC error */ + } + + /* For write case: SDCBUSY and Xfer_Comp will assert when DAT0 not busy. + For read case : SDCBUSY and Xfer_Comp will assert when last byte read out from FIFO. + */ + + /* try not to wait xfer_comp interrupt. + the next command will check SDC_BUSY. + SDC_BUSY means xfer_comp assert + */ + + } // PIO mode + + /* Last: stop transfer */ + if (data->stop){ + if (msdc_do_command(host, data->stop, 0, CMD_TIMEOUT) != 0) { + goto done; + } + } + } + +done: + if (data != NULL) { + host->data = NULL; + host->dma_xfer = 0; + if (dma != 0) { + msdc_dma_off(); + host->dma.used_bd = 0; + host->dma.used_gpd = 0; + dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len, dir); + } + host->blksz = 0; + +#if 0 // don't stop twice! + if(host->hw->flags & MSDC_REMOVABLE && data->error) { + msdc_abort_data(host); + /* reset in IRQ, stop command has issued. -> No need */ + } +#endif + + N_MSG(OPS, "CMD<%d> data<%s %s> blksz<%d> block<%d> error<%d>",cmd->opcode, (dma? "dma":"pio"), + (read ? "read ":"write") ,data->blksz, data->blocks, data->error); + } + +#if 0 /* --- by chhung */ +#if 1 + //if(host->id==1) { + if(send_type==SND_CMD) { + if(cmd->opcode == MMC_SEND_STATUS) { + if((cmd->resp[0] & CARD_READY_FOR_DATA) ||(CARD_CURRENT_STATE(cmd->resp[0]) != 7)){ + N_MSG(OPS,"disable clock, CMD13 IDLE"); + msdc_gate_clock(host->id); + } + } else { + N_MSG(OPS,"disable clock, CMD<%d>", cmd->opcode); + msdc_gate_clock(host->id); + } + } else { + if(read) { + N_MSG(OPS,"disable clock!!! Read CMD<%d>",cmd->opcode); + msdc_gate_clock(host->id); + } + } + //} +#else + msdc_gate_clock(host->id); +#endif +#endif /* end of --- */ + + if (mrq->cmd->error) host->error = 0x001; + if (mrq->data && mrq->data->error) host->error |= 0x010; + if (mrq->stop && mrq->stop->error) host->error |= 0x100; + + //if (host->error) ERR_MSG("host->error<%d>", host->error); + + return host->error; +} + +static int msdc_app_cmd(struct mmc_host *mmc, struct msdc_host *host) +{ + struct mmc_command cmd; + struct mmc_request mrq; + u32 err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + cmd.opcode = MMC_APP_CMD; +#if 0 /* bug: we meet mmc->card is null when ACMD6 */ + cmd.arg = mmc->card->rca << 16; +#else + cmd.arg = host->app_cmd_arg; +#endif + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + + memset(&mrq, 0, sizeof(struct mmc_request)); + mrq.cmd = &cmd; cmd.mrq = &mrq; + cmd.data = NULL; + + err = msdc_do_command(host, &cmd, 0, CMD_TIMEOUT); + return err; +} + +static int msdc_tune_cmdrsp(struct msdc_host*host, struct mmc_command *cmd) +{ + int result = -1; + u32 base = host->base; + u32 rsmpl, cur_rsmpl, orig_rsmpl; + u32 rrdly, cur_rrdly = 0xffffffff, orig_rrdly; + u32 skip = 1; + + /* ==== don't support 3.0 now ==== + 1: R_SMPL[1] + 2: PAD_CMD_RESP_RXDLY[26:22] + ==========================*/ + + // save the previous tune result + sdr_get_field(MSDC_IOCON, MSDC_IOCON_RSPL, orig_rsmpl); + sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, orig_rrdly); + + rrdly = 0; + do { + for (rsmpl = 0; rsmpl < 2; rsmpl++) { + /* Lv1: R_SMPL[1] */ + cur_rsmpl = (orig_rsmpl + rsmpl) % 2; + if (skip == 1) { + skip = 0; + continue; + } + sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, cur_rsmpl); + + if (host->app_cmd) { + result = msdc_app_cmd(host->mmc, host); + if (result) { + ERR_MSG("TUNE_CMD app_cmd<%d> failed: RESP_RXDLY<%d>,R_SMPL<%d>", + host->mrq->cmd->opcode, cur_rrdly, cur_rsmpl); + continue; + } + } + result = msdc_do_command(host, cmd, 0, CMD_TIMEOUT); // not tune. + ERR_MSG("TUNE_CMD<%d> %s PAD_CMD_RESP_RXDLY[26:22]<%d> R_SMPL[1]<%d>", cmd->opcode, + (result == 0) ? "PASS" : "FAIL", cur_rrdly, cur_rsmpl); + + if (result == 0) { + return 0; + } + if (result != (unsigned int)(-EIO)) { + ERR_MSG("TUNE_CMD<%d> Error<%d> not -EIO", cmd->opcode, result); + return result; + } + + /* should be EIO */ + if (sdr_read32(SDC_CMD) & 0x1800) { /* check if has data phase */ + msdc_abort_data(host); + } + } + + /* Lv2: PAD_CMD_RESP_RXDLY[26:22] */ + cur_rrdly = (orig_rrdly + rrdly + 1) % 32; + sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRRDLY, cur_rrdly); + }while (++rrdly < 32); + + return result; +} + +/* Support SD2.0 Only */ +static int msdc_tune_bread(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct msdc_host *host = mmc_priv(mmc); + u32 base = host->base; + u32 ddr=0; + u32 dcrc=0; + u32 rxdly, cur_rxdly0, cur_rxdly1; + u32 dsmpl, cur_dsmpl, orig_dsmpl; + u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3; + u32 cur_dat4, cur_dat5, cur_dat6, cur_dat7; + u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3; + u32 orig_dat4, orig_dat5, orig_dat6, orig_dat7; + int result = -1; + u32 skip = 1; + + sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl); + + /* Tune Method 2. */ + sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); + + rxdly = 0; + do { + for (dsmpl = 0; dsmpl < 2; dsmpl++) { + cur_dsmpl = (orig_dsmpl + dsmpl) % 2; + if (skip == 1) { + skip = 0; + continue; + } + sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl); + + if (host->app_cmd) { + result = msdc_app_cmd(host->mmc, host); + if (result) { + ERR_MSG("TUNE_BREAD app_cmd<%d> failed", host->mrq->cmd->opcode); + continue; + } + } + result = msdc_do_request(mmc,mrq); + + sdr_get_field(SDC_DCRC_STS, SDC_DCRC_STS_POS|SDC_DCRC_STS_NEG, dcrc); /* RO */ + if (!ddr) dcrc &= ~SDC_DCRC_STS_NEG; + ERR_MSG("TUNE_BREAD<%s> dcrc<0x%x> DATRDDLY0/1<0x%x><0x%x> dsmpl<0x%x>", + (result == 0 && dcrc == 0) ? "PASS" : "FAIL", dcrc, + sdr_read32(MSDC_DAT_RDDLY0), sdr_read32(MSDC_DAT_RDDLY1), cur_dsmpl); + + /* Fix me: result is 0, but dcrc is still exist */ + if (result == 0 && dcrc == 0) { + goto done; + } else { + /* there is a case: command timeout, and data phase not processed */ + if (mrq->data->error != 0 && mrq->data->error != (unsigned int)(-EIO)) { + ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>", + result, mrq->cmd->error, mrq->data->error); + goto done; + } + } + } + + cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0); + cur_rxdly1 = sdr_read32(MSDC_DAT_RDDLY1); + + /* E1 ECO. YD: Reverse */ + if (sdr_read32(MSDC_ECO_VER) >= 4) { + orig_dat0 = (cur_rxdly0 >> 24) & 0x1F; + orig_dat1 = (cur_rxdly0 >> 16) & 0x1F; + orig_dat2 = (cur_rxdly0 >> 8) & 0x1F; + orig_dat3 = (cur_rxdly0 >> 0) & 0x1F; + orig_dat4 = (cur_rxdly1 >> 24) & 0x1F; + orig_dat5 = (cur_rxdly1 >> 16) & 0x1F; + orig_dat6 = (cur_rxdly1 >> 8) & 0x1F; + orig_dat7 = (cur_rxdly1 >> 0) & 0x1F; + } else { + orig_dat0 = (cur_rxdly0 >> 0) & 0x1F; + orig_dat1 = (cur_rxdly0 >> 8) & 0x1F; + orig_dat2 = (cur_rxdly0 >> 16) & 0x1F; + orig_dat3 = (cur_rxdly0 >> 24) & 0x1F; + orig_dat4 = (cur_rxdly1 >> 0) & 0x1F; + orig_dat5 = (cur_rxdly1 >> 8) & 0x1F; + orig_dat6 = (cur_rxdly1 >> 16) & 0x1F; + orig_dat7 = (cur_rxdly1 >> 24) & 0x1F; + } + + if (ddr) { + cur_dat0 = (dcrc & (1 << 0) || dcrc & (1 << 8)) ? ((orig_dat0 + 1) % 32) : orig_dat0; + cur_dat1 = (dcrc & (1 << 1) || dcrc & (1 << 9)) ? ((orig_dat1 + 1) % 32) : orig_dat1; + cur_dat2 = (dcrc & (1 << 2) || dcrc & (1 << 10)) ? ((orig_dat2 + 1) % 32) : orig_dat2; + cur_dat3 = (dcrc & (1 << 3) || dcrc & (1 << 11)) ? ((orig_dat3 + 1) % 32) : orig_dat3; + } else { + cur_dat0 = (dcrc & (1 << 0)) ? ((orig_dat0 + 1) % 32) : orig_dat0; + cur_dat1 = (dcrc & (1 << 1)) ? ((orig_dat1 + 1) % 32) : orig_dat1; + cur_dat2 = (dcrc & (1 << 2)) ? ((orig_dat2 + 1) % 32) : orig_dat2; + cur_dat3 = (dcrc & (1 << 3)) ? ((orig_dat3 + 1) % 32) : orig_dat3; + } + cur_dat4 = (dcrc & (1 << 4)) ? ((orig_dat4 + 1) % 32) : orig_dat4; + cur_dat5 = (dcrc & (1 << 5)) ? ((orig_dat5 + 1) % 32) : orig_dat5; + cur_dat6 = (dcrc & (1 << 6)) ? ((orig_dat6 + 1) % 32) : orig_dat6; + cur_dat7 = (dcrc & (1 << 7)) ? ((orig_dat7 + 1) % 32) : orig_dat7; + + cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0); + cur_rxdly1 = (cur_dat4 << 24) | (cur_dat5 << 16) | (cur_dat6 << 8) | (cur_dat7 << 0); + + sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0); + sdr_write32(MSDC_DAT_RDDLY1, cur_rxdly1); + + } while (++rxdly < 32); + +done: + return result; +} + +static int msdc_tune_bwrite(struct mmc_host *mmc,struct mmc_request *mrq) +{ + struct msdc_host *host = mmc_priv(mmc); + u32 base = host->base; + + u32 wrrdly, cur_wrrdly = 0xffffffff, orig_wrrdly; + u32 dsmpl, cur_dsmpl, orig_dsmpl; + u32 rxdly, cur_rxdly0; + u32 orig_dat0, orig_dat1, orig_dat2, orig_dat3; + u32 cur_dat0, cur_dat1, cur_dat2, cur_dat3; + int result = -1; + u32 skip = 1; + + // MSDC_IOCON_DDR50CKD need to check. [Fix me] + + sdr_get_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, orig_wrrdly); + sdr_get_field(MSDC_IOCON, MSDC_IOCON_DSPL, orig_dsmpl ); + + /* Tune Method 2. just DAT0 */ + sdr_set_field(MSDC_IOCON, MSDC_IOCON_DDLSEL, 1); + cur_rxdly0 = sdr_read32(MSDC_DAT_RDDLY0); + + /* E1 ECO. YD: Reverse */ + if (sdr_read32(MSDC_ECO_VER) >= 4) { + orig_dat0 = (cur_rxdly0 >> 24) & 0x1F; + orig_dat1 = (cur_rxdly0 >> 16) & 0x1F; + orig_dat2 = (cur_rxdly0 >> 8) & 0x1F; + orig_dat3 = (cur_rxdly0 >> 0) & 0x1F; + } else { + orig_dat0 = (cur_rxdly0 >> 0) & 0x1F; + orig_dat1 = (cur_rxdly0 >> 8) & 0x1F; + orig_dat2 = (cur_rxdly0 >> 16) & 0x1F; + orig_dat3 = (cur_rxdly0 >> 24) & 0x1F; + } + + rxdly = 0; + do { + wrrdly = 0; + do { + for (dsmpl = 0; dsmpl < 2; dsmpl++) { + cur_dsmpl = (orig_dsmpl + dsmpl) % 2; + if (skip == 1) { + skip = 0; + continue; + } + sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, cur_dsmpl); + + if (host->app_cmd) { + result = msdc_app_cmd(host->mmc, host); + if (result) { + ERR_MSG("TUNE_BWRITE app_cmd<%d> failed", host->mrq->cmd->opcode); + continue; + } + } + result = msdc_do_request(mmc,mrq); + + ERR_MSG("TUNE_BWRITE<%s> DSPL<%d> DATWRDLY<%d> MSDC_DAT_RDDLY0<0x%x>", + result == 0 ? "PASS" : "FAIL", + cur_dsmpl, cur_wrrdly, cur_rxdly0); + + if (result == 0) { + goto done; + } + else { + /* there is a case: command timeout, and data phase not processed */ + if (mrq->data->error != (unsigned int)(-EIO)) { + ERR_MSG("TUNE_READ: result<0x%x> cmd_error<%d> data_error<%d>", + result, mrq->cmd->error, mrq->data->error); + goto done; + } + } + } + cur_wrrdly = (orig_wrrdly + wrrdly + 1) % 32; + sdr_set_field(MSDC_PAD_TUNE, MSDC_PAD_TUNE_DATWRDLY, cur_wrrdly); + } while (++wrrdly < 32); + + cur_dat0 = (orig_dat0 + rxdly) % 32; /* only adjust bit-1 for crc */ + cur_dat1 = orig_dat1; + cur_dat2 = orig_dat2; + cur_dat3 = orig_dat3; + + cur_rxdly0 = (cur_dat0 << 24) | (cur_dat1 << 16) | (cur_dat2 << 8) | (cur_dat3 << 0); + sdr_write32(MSDC_DAT_RDDLY0, cur_rxdly0); + } while (++rxdly < 32); + +done: + return result; +} + +static int msdc_get_card_status(struct mmc_host *mmc, struct msdc_host *host, u32 *status) +{ + struct mmc_command cmd; + struct mmc_request mrq; + u32 err; + + memset(&cmd, 0, sizeof(struct mmc_command)); + cmd.opcode = MMC_SEND_STATUS; + if (mmc->card) { + cmd.arg = mmc->card->rca << 16; + } else { + ERR_MSG("cmd13 mmc card is null"); + cmd.arg = host->app_cmd_arg; + } + cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; + + memset(&mrq, 0, sizeof(struct mmc_request)); + mrq.cmd = &cmd; cmd.mrq = &mrq; + cmd.data = NULL; + + err = msdc_do_command(host, &cmd, 1, CMD_TIMEOUT); + + if (status) { + *status = cmd.resp[0]; + } + + return err; +} + +static int msdc_check_busy(struct mmc_host *mmc, struct msdc_host *host) +{ + u32 err = 0; + u32 status = 0; + + do { + err = msdc_get_card_status(mmc, host, &status); + if (err) return err; + /* need cmd12? */ + ERR_MSG("cmd<13> resp<0x%x>", status); + } while (R1_CURRENT_STATE(status) == 7); + + return err; +} + +/* failed when msdc_do_request */ +static int msdc_tune_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct msdc_host *host = mmc_priv(mmc); + struct mmc_command *cmd; + struct mmc_data *data; + //u32 base = host->base; + int ret=0, read; + + cmd = mrq->cmd; + data = mrq->cmd->data; + + read = data->flags & MMC_DATA_READ ? 1 : 0; + + if (read) { + if (data->error == (unsigned int)(-EIO)) { + ret = msdc_tune_bread(mmc,mrq); + } + } else { + ret = msdc_check_busy(mmc, host); + if (ret){ + ERR_MSG("XXX cmd13 wait program done failed"); + return ret; + } + /* CRC and TO */ + /* Fix me: don't care card status? */ + ret = msdc_tune_bwrite(mmc,mrq); + } + + return ret; +} + +/* ops.request */ +static void msdc_ops_request(struct mmc_host *mmc,struct mmc_request *mrq) +{ + struct msdc_host *host = mmc_priv(mmc); + + //=== for sdio profile === +#if 0 /* --- by chhung */ + u32 old_H32, old_L32, new_H32, new_L32; + u32 ticks = 0, opcode = 0, sizes = 0, bRx = 0; +#endif /* end of --- */ + + if(host->mrq){ + ERR_MSG("XXX host->mrq<0x%.8x>", (int)host->mrq); + BUG(); + } + + if (!is_card_present(host) || host->power_mode == MMC_POWER_OFF) { + ERR_MSG("cmd<%d> card<%d> power<%d>", mrq->cmd->opcode, is_card_present(host), host->power_mode); + mrq->cmd->error = (unsigned int)-ENOMEDIUM; + +#if 1 + mrq->done(mrq); // call done directly. +#else + mrq->cmd->retries = 0; // please don't retry. + mmc_request_done(mmc, mrq); +#endif + + return; + } + + /* start to process */ + spin_lock(&host->lock); +#if 0 /* --- by chhung */ + if (sdio_pro_enable) { //=== for sdio profile === + if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53) { + GPT_GetCounter64(&old_L32, &old_H32); + } + } +#endif /* end of --- */ + + host->mrq = mrq; + + if (msdc_do_request(mmc,mrq)) { + if(host->hw->flags & MSDC_REMOVABLE && ralink_soc == MT762X_SOC_MT7621AT && mrq->data && mrq->data->error) { + msdc_tune_request(mmc,mrq); + } + } + + /* ==== when request done, check if app_cmd ==== */ + if (mrq->cmd->opcode == MMC_APP_CMD) { + host->app_cmd = 1; + host->app_cmd_arg = mrq->cmd->arg; /* save the RCA */ + } else { + host->app_cmd = 0; + //host->app_cmd_arg = 0; + } + + host->mrq = NULL; + +#if 0 /* --- by chhung */ + //=== for sdio profile === + if (sdio_pro_enable) { + if (mrq->cmd->opcode == 52 || mrq->cmd->opcode == 53) { + GPT_GetCounter64(&new_L32, &new_H32); + ticks = msdc_time_calc(old_L32, old_H32, new_L32, new_H32); + + opcode = mrq->cmd->opcode; + if (mrq->cmd->data) { + sizes = mrq->cmd->data->blocks * mrq->cmd->data->blksz; + bRx = mrq->cmd->data->flags & MMC_DATA_READ ? 1 : 0 ; + } else { + bRx = mrq->cmd->arg & 0x80000000 ? 1 : 0; + } + + if (!mrq->cmd->error) { + msdc_performance(opcode, sizes, bRx, ticks); + } + } + } +#endif /* end of --- */ + spin_unlock(&host->lock); + + mmc_request_done(mmc, mrq); + + return; +} + +/* called by ops.set_ios */ +static void msdc_set_buswidth(struct msdc_host *host, u32 width) +{ + u32 base = host->base; + u32 val = sdr_read32(SDC_CFG); + + val &= ~SDC_CFG_BUSWIDTH; + + switch (width) { + default: + case MMC_BUS_WIDTH_1: + width = 1; + val |= (MSDC_BUS_1BITS << 16); + break; + case MMC_BUS_WIDTH_4: + val |= (MSDC_BUS_4BITS << 16); + break; + case MMC_BUS_WIDTH_8: + val |= (MSDC_BUS_8BITS << 16); + break; + } + + sdr_write32(SDC_CFG, val); + + N_MSG(CFG, "Bus Width = %d", width); +} + +/* ops.set_ios */ +static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct msdc_host *host = mmc_priv(mmc); + struct msdc_hw *hw=host->hw; + u32 base = host->base; + u32 ddr = 0; + +#ifdef MT6575_SD_DEBUG + static char *vdd[] = { + "1.50v", "1.55v", "1.60v", "1.65v", "1.70v", "1.80v", "1.90v", + "2.00v", "2.10v", "2.20v", "2.30v", "2.40v", "2.50v", "2.60v", + "2.70v", "2.80v", "2.90v", "3.00v", "3.10v", "3.20v", "3.30v", + "3.40v", "3.50v", "3.60v" + }; + static char *power_mode[] = { + "OFF", "UP", "ON" + }; + static char *bus_mode[] = { + "UNKNOWN", "OPENDRAIN", "PUSHPULL" + }; + static char *timing[] = { + "LEGACY", "MMC_HS", "SD_HS" + }; + + printk("SET_IOS: CLK(%dkHz), BUS(%s), BW(%u), PWR(%s), VDD(%s), TIMING(%s)", + ios->clock / 1000, bus_mode[ios->bus_mode], + (ios->bus_width == MMC_BUS_WIDTH_4) ? 4 : 1, + power_mode[ios->power_mode], vdd[ios->vdd], timing[ios->timing]); +#endif + + msdc_set_buswidth(host, ios->bus_width); + + /* Power control ??? */ + switch (ios->power_mode) { + case MMC_POWER_OFF: + case MMC_POWER_UP: + // msdc_set_power_mode(host, ios->power_mode); /* --- by chhung */ + break; + case MMC_POWER_ON: + host->power_mode = MMC_POWER_ON; + break; + default: + break; + } + + /* Clock control */ + if (host->mclk != ios->clock) { + if(ios->clock > 25000000) { + //if (!(host->hw->flags & MSDC_REMOVABLE)) { + INIT_MSG("SD data latch edge<%d>", hw->data_edge); + sdr_set_field(MSDC_IOCON, MSDC_IOCON_RSPL, hw->cmd_edge); + sdr_set_field(MSDC_IOCON, MSDC_IOCON_DSPL, hw->data_edge); + //} /* for tuning debug */ + } else { /* default value */ + sdr_write32(MSDC_IOCON, 0x00000000); + // sdr_write32(MSDC_DAT_RDDLY0, 0x00000000); + sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward + sdr_write32(MSDC_DAT_RDDLY1, 0x00000000); + // sdr_write32(MSDC_PAD_TUNE, 0x00000000); + sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward + } + msdc_set_mclk(host, ddr, ios->clock); + } +} + +/* ops.get_ro */ +static int msdc_ops_get_ro(struct mmc_host *mmc) +{ + struct msdc_host *host = mmc_priv(mmc); + u32 base = host->base; + unsigned long flags; + int ro = 0; + + if (host->hw->flags & MSDC_WP_PIN_EN) { /* set for card */ + spin_lock_irqsave(&host->lock, flags); + ro = (sdr_read32(MSDC_PS) >> 31); + spin_unlock_irqrestore(&host->lock, flags); + } + return ro; +} + +/* ops.get_cd */ +static int msdc_ops_get_cd(struct mmc_host *mmc) +{ + struct msdc_host *host = mmc_priv(mmc); + u32 base = host->base; + unsigned long flags; + int present = 1; + + /* for sdio, MSDC_REMOVABLE not set, always return 1 */ + if (!(host->hw->flags & MSDC_REMOVABLE)) { + /* For sdio, read H/W always get<1>, but may timeout some times */ +#if 1 + host->card_inserted = 1; + return 1; +#else + host->card_inserted = (host->pm_state.event == PM_EVENT_USER_RESUME) ? 1 : 0; + INIT_MSG("sdio ops_get_cd<%d>", host->card_inserted); + return host->card_inserted; +#endif + } + + /* MSDC_CD_PIN_EN set for card */ + if (host->hw->flags & MSDC_CD_PIN_EN) { + spin_lock_irqsave(&host->lock, flags); +#if 0 + present = host->card_inserted; /* why not read from H/W: Fix me*/ +#else + // CD + if (cd_active_low) + present = (sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 0 : 1; + else + present = (sdr_read32(MSDC_PS) & MSDC_PS_CDSTS) ? 1 : 0; + host->card_inserted = present; +#endif + spin_unlock_irqrestore(&host->lock, flags); + } else { + present = 0; /* TODO? Check DAT3 pins for card detection */ + } + + INIT_MSG("ops_get_cd return<%d>", present); + return present; +} + +/* ops.enable_sdio_irq */ +static void msdc_ops_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct msdc_host *host = mmc_priv(mmc); + struct msdc_hw *hw = host->hw; + u32 base = host->base; + u32 tmp; + + if (hw->flags & MSDC_EXT_SDIO_IRQ) { /* yes for sdio */ + if (enable) { + hw->enable_sdio_eirq(); /* combo_sdio_enable_eirq */ + } else { + hw->disable_sdio_eirq(); /* combo_sdio_disable_eirq */ + } + } else { + ERR_MSG("XXX "); /* so never enter here */ + tmp = sdr_read32(SDC_CFG); + /* FIXME. Need to interrupt gap detection */ + if (enable) { + tmp |= (SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP); + } else { + tmp &= ~(SDC_CFG_SDIOIDE | SDC_CFG_SDIOINTWKUP); + } + sdr_write32(SDC_CFG, tmp); + } +} + +static struct mmc_host_ops mt_msdc_ops = { + .request = msdc_ops_request, + .set_ios = msdc_ops_set_ios, + .get_ro = msdc_ops_get_ro, + .get_cd = msdc_ops_get_cd, + .enable_sdio_irq = msdc_ops_enable_sdio_irq, +}; + +/*--------------------------------------------------------------------------*/ +/* interrupt handler */ +/*--------------------------------------------------------------------------*/ +static irqreturn_t msdc_irq(int irq, void *dev_id) +{ + struct msdc_host *host = (struct msdc_host *)dev_id; + struct mmc_data *data = host->data; + struct mmc_command *cmd = host->cmd; + u32 base = host->base; + + u32 cmdsts = MSDC_INT_RSPCRCERR | MSDC_INT_CMDTMO | MSDC_INT_CMDRDY | + MSDC_INT_ACMDCRCERR | MSDC_INT_ACMDTMO | MSDC_INT_ACMDRDY | + MSDC_INT_ACMD19_DONE; + u32 datsts = MSDC_INT_DATCRCERR |MSDC_INT_DATTMO; + + u32 intsts = sdr_read32(MSDC_INT); + u32 inten = sdr_read32(MSDC_INTEN); inten &= intsts; + + sdr_write32(MSDC_INT, intsts); /* clear interrupts */ + /* MSG will cause fatal error */ + + /* card change interrupt */ + if (intsts & MSDC_INT_CDSC){ + if (mtk_sw_poll) + return IRQ_HANDLED; + IRQ_MSG("MSDC_INT_CDSC irq<0x%.8x>", intsts); +#if 0 /* ---/+++ by chhung: fix slot mechanical bounce issue */ + tasklet_hi_schedule(&host->card_tasklet); +#else + schedule_delayed_work(&host->card_delaywork, HZ); +#endif + /* tuning when plug card ? */ + } + + /* sdio interrupt */ + if (intsts & MSDC_INT_SDIOIRQ){ + IRQ_MSG("XXX MSDC_INT_SDIOIRQ"); /* seems not sdio irq */ + //mmc_signal_sdio_irq(host->mmc); + } + + /* transfer complete interrupt */ + if (data != NULL) { + if (inten & MSDC_INT_XFER_COMPL) { + data->bytes_xfered = host->dma.xfersz; + complete(&host->xfer_done); + } + + if (intsts & datsts) { + /* do basic reset, or stop command will sdc_busy */ + msdc_reset(); + msdc_clr_fifo(); + msdc_clr_int(); + atomic_set(&host->abort, 1); /* For PIO mode exit */ + + if (intsts & MSDC_INT_DATTMO){ + IRQ_MSG("XXX CMD<%d> MSDC_INT_DATTMO", host->mrq->cmd->opcode); + data->error = (unsigned int)-ETIMEDOUT; + } + else if (intsts & MSDC_INT_DATCRCERR){ + IRQ_MSG("XXX CMD<%d> MSDC_INT_DATCRCERR, SDC_DCRC_STS<0x%x>", host->mrq->cmd->opcode, sdr_read32(SDC_DCRC_STS)); + data->error = (unsigned int)-EIO; + } + + //if(sdr_read32(MSDC_INTEN) & MSDC_INT_XFER_COMPL) { + if (host->dma_xfer) { + complete(&host->xfer_done); /* Read CRC come fast, XFER_COMPL not enabled */ + } /* PIO mode can't do complete, because not init */ + } + } + + /* command interrupts */ + if ((cmd != NULL) && (intsts & cmdsts)) { + if ((intsts & MSDC_INT_CMDRDY) || (intsts & MSDC_INT_ACMDRDY) || + (intsts & MSDC_INT_ACMD19_DONE)) { + u32 *rsp = &cmd->resp[0]; + + switch (host->cmd_rsp) { + case RESP_NONE: + break; + case RESP_R2: + *rsp++ = sdr_read32(SDC_RESP3); *rsp++ = sdr_read32(SDC_RESP2); + *rsp++ = sdr_read32(SDC_RESP1); *rsp++ = sdr_read32(SDC_RESP0); + break; + default: /* Response types 1, 3, 4, 5, 6, 7(1b) */ + if ((intsts & MSDC_INT_ACMDRDY) || (intsts & MSDC_INT_ACMD19_DONE)) { + *rsp = sdr_read32(SDC_ACMD_RESP); + } else { + *rsp = sdr_read32(SDC_RESP0); + } + break; + } + } else if ((intsts & MSDC_INT_RSPCRCERR) || (intsts & MSDC_INT_ACMDCRCERR)) { + if(intsts & MSDC_INT_ACMDCRCERR){ + IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDCRCERR",cmd->opcode); + } + else { + IRQ_MSG("XXX CMD<%d> MSDC_INT_RSPCRCERR",cmd->opcode); + } + cmd->error = (unsigned int)-EIO; + } else if ((intsts & MSDC_INT_CMDTMO) || (intsts & MSDC_INT_ACMDTMO)) { + if(intsts & MSDC_INT_ACMDTMO){ + IRQ_MSG("XXX CMD<%d> MSDC_INT_ACMDTMO",cmd->opcode); + } + else { + IRQ_MSG("XXX CMD<%d> MSDC_INT_CMDTMO",cmd->opcode); + } + cmd->error = (unsigned int)-ETIMEDOUT; + msdc_reset(); + msdc_clr_fifo(); + msdc_clr_int(); + } + complete(&host->cmd_done); + } + + /* mmc irq interrupts */ + if (intsts & MSDC_INT_MMCIRQ) { + printk(KERN_INFO "msdc[%d] MMCIRQ: SDC_CSTS=0x%.8x\r\n", host->id, sdr_read32(SDC_CSTS)); + } + +#ifdef MT6575_SD_DEBUG + { +/* msdc_int_reg *int_reg = (msdc_int_reg*)&intsts;*/ + N_MSG(INT, "IRQ_EVT(0x%x): MMCIRQ(%d) CDSC(%d), ACRDY(%d), ACTMO(%d), ACCRE(%d) AC19DN(%d)", + intsts, + int_reg->mmcirq, + int_reg->cdsc, + int_reg->atocmdrdy, + int_reg->atocmdtmo, + int_reg->atocmdcrc, + int_reg->atocmd19done); + N_MSG(INT, "IRQ_EVT(0x%x): SDIO(%d) CMDRDY(%d), CMDTMO(%d), RSPCRC(%d), CSTA(%d)", + intsts, + int_reg->sdioirq, + int_reg->cmdrdy, + int_reg->cmdtmo, + int_reg->rspcrc, + int_reg->csta); + N_MSG(INT, "IRQ_EVT(0x%x): XFCMP(%d) DXDONE(%d), DATTMO(%d), DATCRC(%d), DMAEMP(%d)", + intsts, + int_reg->xfercomp, + int_reg->dxferdone, + int_reg->dattmo, + int_reg->datcrc, + int_reg->dmaqempty); + + } +#endif + + return IRQ_HANDLED; +} + +/*--------------------------------------------------------------------------*/ +/* platform_driver members */ +/*--------------------------------------------------------------------------*/ +/* called by msdc_drv_probe/remove */ +static void msdc_enable_cd_irq(struct msdc_host *host, int enable) +{ + struct msdc_hw *hw = host->hw; + u32 base = host->base; + + /* for sdio, not set */ + if ((hw->flags & MSDC_CD_PIN_EN) == 0) { + /* Pull down card detection pin since it is not avaiable */ + /* + if (hw->config_gpio_pin) + hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN); + */ + sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); + sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC); + sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP); + return; + } + + N_MSG(CFG, "CD IRQ Eanable(%d)", enable); + + if (enable) { + if (hw->enable_cd_eirq) { /* not set, never enter */ + hw->enable_cd_eirq(); + } else { + /* card detection circuit relies on the core power so that the core power + * shouldn't be turned off. Here adds a reference count to keep + * the core power alive. + */ + //msdc_vcore_on(host); //did in msdc_init_hw() + + if (hw->config_gpio_pin) /* NULL */ + hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_UP); + + sdr_set_field(MSDC_PS, MSDC_PS_CDDEBOUNCE, DEFAULT_DEBOUNCE); + sdr_set_bits(MSDC_PS, MSDC_PS_CDEN); + sdr_set_bits(MSDC_INTEN, MSDC_INTEN_CDSC); + sdr_set_bits(SDC_CFG, SDC_CFG_INSWKUP); /* not in document! Fix me */ + } + } else { + if (hw->disable_cd_eirq) { + hw->disable_cd_eirq(); + } else { + if (hw->config_gpio_pin) /* NULL */ + hw->config_gpio_pin(MSDC_CD_PIN, GPIO_PULL_DOWN); + + sdr_clr_bits(SDC_CFG, SDC_CFG_INSWKUP); + sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); + sdr_clr_bits(MSDC_INTEN, MSDC_INTEN_CDSC); + + /* Here decreases a reference count to core power since card + * detection circuit is shutdown. + */ + //msdc_vcore_off(host); + } + } +} + +/* called by msdc_drv_probe */ +static void msdc_init_hw(struct msdc_host *host) +{ + u32 base = host->base; + struct msdc_hw *hw = host->hw; + +#ifdef MT6575_SD_DEBUG + msdc_reg[host->id] = (struct msdc_regs *)host->base; +#endif + + /* Power on */ +#if 0 /* --- by chhung */ + msdc_vcore_on(host); + msdc_pin_reset(host, MSDC_PIN_PULL_UP); + msdc_select_clksrc(host, hw->clk_src); + enable_clock(PERI_MSDC0_PDN + host->id, "SD"); + msdc_vdd_on(host); +#endif /* end of --- */ + /* Configure to MMC/SD mode */ + sdr_set_field(MSDC_CFG, MSDC_CFG_MODE, MSDC_SDMMC); + + /* Reset */ + msdc_reset(); + msdc_clr_fifo(); + + /* Disable card detection */ + sdr_clr_bits(MSDC_PS, MSDC_PS_CDEN); + + /* Disable and clear all interrupts */ + sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN)); + sdr_write32(MSDC_INT, sdr_read32(MSDC_INT)); + +#if 1 + /* reset tuning parameter */ + sdr_write32(MSDC_PAD_CTL0, 0x00090000); + sdr_write32(MSDC_PAD_CTL1, 0x000A0000); + sdr_write32(MSDC_PAD_CTL2, 0x000A0000); + // sdr_write32(MSDC_PAD_TUNE, 0x00000000); + sdr_write32(MSDC_PAD_TUNE, 0x84101010); // for MT7620 E2 and afterward + // sdr_write32(MSDC_DAT_RDDLY0, 0x00000000); + sdr_write32(MSDC_DAT_RDDLY0, 0x10101010); // for MT7620 E2 and afterward + sdr_write32(MSDC_DAT_RDDLY1, 0x00000000); + sdr_write32(MSDC_IOCON, 0x00000000); +#if 0 // use MT7620 default value: 0x403c004f + sdr_write32(MSDC_PATCH_BIT0, 0x003C000F); /* bit0 modified: Rx Data Clock Source: 1 -> 2.0*/ +#endif + + if (sdr_read32(MSDC_ECO_VER) >= 4) { + if (host->id == 1) { + sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_WRDAT_CRCS, 1); + sdr_set_field(MSDC_PATCH_BIT1, MSDC_PATCH_BIT1_CMD_RSP, 1); + + /* internal clock: latch read data */ + sdr_set_bits(MSDC_PATCH_BIT0, MSDC_PATCH_BIT_CKGEN_CK); + } + } +#endif + + /* for safety, should clear SDC_CFG.SDIO_INT_DET_EN & set SDC_CFG.SDIO in + pre-loader,uboot,kernel drivers. and SDC_CFG.SDIO_INT_DET_EN will be only + set when kernel driver wants to use SDIO bus interrupt */ + /* Configure to enable SDIO mode. it's must otherwise sdio cmd5 failed */ + sdr_set_bits(SDC_CFG, SDC_CFG_SDIO); + + /* disable detect SDIO device interupt function */ + sdr_clr_bits(SDC_CFG, SDC_CFG_SDIOIDE); + + /* eneable SMT for glitch filter */ + sdr_set_bits(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKSMT); + sdr_set_bits(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDSMT); + sdr_set_bits(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATSMT); + +#if 1 + /* set clk, cmd, dat pad driving */ + sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, hw->clk_drv); + sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, hw->clk_drv); + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, hw->cmd_drv); + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, hw->cmd_drv); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, hw->dat_drv); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, hw->dat_drv); +#else + sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVN, 0); + sdr_set_field(MSDC_PAD_CTL0, MSDC_PAD_CTL0_CLKDRVP, 0); + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVN, 0); + sdr_set_field(MSDC_PAD_CTL1, MSDC_PAD_CTL1_CMDDRVP, 0); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVN, 0); + sdr_set_field(MSDC_PAD_CTL2, MSDC_PAD_CTL2_DATDRVP, 0); +#endif + + /* set sampling edge */ + + /* write crc timeout detection */ + sdr_set_field(MSDC_PATCH_BIT0, 1 << 30, 1); + + /* Configure to default data timeout */ + sdr_set_field(SDC_CFG, SDC_CFG_DTOC, DEFAULT_DTOC); + + msdc_set_buswidth(host, MMC_BUS_WIDTH_1); + + N_MSG(FUC, "init hardware done!"); +} + +/* called by msdc_drv_remove */ +static void msdc_deinit_hw(struct msdc_host *host) +{ + u32 base = host->base; + + /* Disable and clear all interrupts */ + sdr_clr_bits(MSDC_INTEN, sdr_read32(MSDC_INTEN)); + sdr_write32(MSDC_INT, sdr_read32(MSDC_INT)); + + /* Disable card detection */ + msdc_enable_cd_irq(host, 0); + // msdc_set_power_mode(host, MMC_POWER_OFF); /* make sure power down */ /* --- by chhung */ +} + +/* init gpd and bd list in msdc_drv_probe */ +static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma) +{ + gpd_t *gpd = dma->gpd; + bd_t *bd = dma->bd; + bd_t *ptr, *prev; + + /* we just support one gpd */ + int bdlen = MAX_BD_PER_GPD; + + /* init the 2 gpd */ + memset(gpd, 0, sizeof(gpd_t) * 2); + //gpd->next = (void *)virt_to_phys(gpd + 1); /* pointer to a null gpd, bug! kmalloc <-> virt_to_phys */ + //gpd->next = (dma->gpd_addr + 1); /* bug */ + gpd->next = (void *)((u32)dma->gpd_addr + sizeof(gpd_t)); + + //gpd->intr = 0; + gpd->bdp = 1; /* hwo, cs, bd pointer */ + //gpd->ptr = (void*)virt_to_phys(bd); + gpd->ptr = (void *)dma->bd_addr; /* physical address */ + + memset(bd, 0, sizeof(bd_t) * bdlen); + ptr = bd + bdlen - 1; + //ptr->eol = 1; /* 0 or 1 [Fix me]*/ + //ptr->next = 0; + + while (ptr != bd) { + prev = ptr - 1; + prev->next = (void *)(dma->bd_addr + sizeof(bd_t) *(ptr - bd)); + ptr = prev; + } +} + +static int msdc_drv_probe(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + __iomem void *base; + struct mmc_host *mmc; + struct resource *mem; + struct msdc_host *host; + struct msdc_hw *hw; + int ret, irq; + + pdev->dev.platform_data = &msdc0_hw; + + if (of_property_read_bool(pdev->dev.of_node, "mtk,wp-en")) + msdc0_hw.flags |= MSDC_WP_PIN_EN; + + /* Allocate MMC host for this device */ + mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev); + if (!mmc) return -ENOMEM; + + hw = (struct msdc_hw*)pdev->dev.platform_data; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + + //BUG_ON((!hw) || (!mem) || (irq < 0)); /* --- by chhung */ + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* Set host parameters to mmc */ + mmc->ops = &mt_msdc_ops; + mmc->f_min = HOST_MIN_MCLK; + mmc->f_max = HOST_MAX_MCLK; + mmc->ocr_avail = MSDC_OCR_AVAIL; + + /* For sd card: MSDC_SYS_SUSPEND | MSDC_WP_PIN_EN | MSDC_CD_PIN_EN | MSDC_REMOVABLE | MSDC_HIGHSPEED, + For sdio : MSDC_EXT_SDIO_IRQ | MSDC_HIGHSPEED */ + if (hw->flags & MSDC_HIGHSPEED) { + mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; + } + if (hw->data_pins == 4) { /* current data_pins are all 4*/ + mmc->caps |= MMC_CAP_4_BIT_DATA; + } else if (hw->data_pins == 8) { + mmc->caps |= MMC_CAP_8_BIT_DATA; + } + if ((hw->flags & MSDC_SDIO_IRQ) || (hw->flags & MSDC_EXT_SDIO_IRQ)) + mmc->caps |= MMC_CAP_SDIO_IRQ; /* yes for sdio */ + + cd_active_low = !of_property_read_bool(pdev->dev.of_node, "mediatek,cd-high"); + mtk_sw_poll = of_property_read_bool(pdev->dev.of_node, "mediatek,cd-poll"); + + if (mtk_sw_poll) + mmc->caps |= MMC_CAP_NEEDS_POLL; + + /* MMC core transfer sizes tunable parameters */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) + mmc->max_segs = MAX_HW_SGMTS; +#else + mmc->max_hw_segs = MAX_HW_SGMTS; + mmc->max_phys_segs = MAX_PHY_SGMTS; +#endif + mmc->max_seg_size = MAX_SGMT_SZ; + mmc->max_blk_size = HOST_MAX_BLKSZ; + mmc->max_req_size = MAX_REQ_SZ; + mmc->max_blk_count = mmc->max_req_size; + + host = mmc_priv(mmc); + host->hw = hw; + host->mmc = mmc; + host->id = pdev->id; + if (host->id < 0 || host->id >= 4) + host->id = 0; + host->error = 0; + host->irq = irq; + host->base = (unsigned long) base; + host->mclk = 0; /* mclk: the request clock of mmc sub-system */ + host->hclk = hclks[hw->clk_src]; /* hclk: clock of clock source to msdc controller */ + host->sclk = 0; /* sclk: the really clock after divition */ + host->pm_state = PMSG_RESUME; + host->suspend = 0; + host->core_clkon = 0; + host->card_clkon = 0; + host->core_power = 0; + host->power_mode = MMC_POWER_OFF; +// host->card_inserted = hw->flags & MSDC_REMOVABLE ? 0 : 1; + host->timeout_ns = 0; + host->timeout_clks = DEFAULT_DTOC * 65536; + + host->mrq = NULL; + //init_MUTEX(&host->sem); /* we don't need to support multiple threads access */ + + host->dma.used_gpd = 0; + host->dma.used_bd = 0; + mmc_dev(mmc)->dma_mask = NULL; + + /* using dma_alloc_coherent*/ /* todo: using 1, for all 4 slots */ + host->dma.gpd = dma_alloc_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), &host->dma.gpd_addr, GFP_KERNEL); + host->dma.bd = dma_alloc_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), &host->dma.bd_addr, GFP_KERNEL); + BUG_ON((!host->dma.gpd) || (!host->dma.bd)); + msdc_init_gpd_bd(host, &host->dma); + /*for emmc*/ + msdc_6575_host[pdev->id] = host; + +#if 0 + tasklet_init(&host->card_tasklet, msdc_tasklet_card, (ulong)host); +#else + INIT_DELAYED_WORK(&host->card_delaywork, msdc_tasklet_card); +#endif + spin_lock_init(&host->lock); + msdc_init_hw(host); + + if (ralink_soc == MT762X_SOC_MT7621AT) + ret = request_irq((unsigned int)irq, msdc_irq, 0, dev_name(&pdev->dev), host); + else + ret = request_irq((unsigned int)irq, msdc_irq, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), host); + + if (ret) goto release; + // mt65xx_irq_unmask(irq); /* --- by chhung */ + + if (hw->flags & MSDC_CD_PIN_EN) { /* not set for sdio */ + if (hw->request_cd_eirq) { /* not set for MT6575 */ + hw->request_cd_eirq(msdc_eirq_cd, (void*)host); /* msdc_eirq_cd will not be used! */ + } + } + + if (hw->request_sdio_eirq) /* set to combo_sdio_request_eirq() for WIFI */ + hw->request_sdio_eirq(msdc_eirq_sdio, (void*)host); /* msdc_eirq_sdio() will be called when EIRQ */ + + if (hw->register_pm) {/* yes for sdio */ +#ifdef CONFIG_PM + hw->register_pm(msdc_pm, (void*)host); /* combo_sdio_register_pm() */ +#endif + if(hw->flags & MSDC_SYS_SUSPEND) { /* will not set for WIFI */ + ERR_MSG("MSDC_SYS_SUSPEND and register_pm both set"); + } + //mmc->pm_flags |= MMC_PM_IGNORE_PM_NOTIFY; /* pm not controlled by system but by client. */ /* --- by chhung */ + } + + platform_set_drvdata(pdev, mmc); + + ret = mmc_add_host(mmc); + if (ret) goto free_irq; + + /* Config card detection pin and enable interrupts */ + if (hw->flags & MSDC_CD_PIN_EN) { /* set for card */ + msdc_enable_cd_irq(host, 1); + } else { + msdc_enable_cd_irq(host, 0); + } + + return 0; + +free_irq: + free_irq(irq, host); +release: + platform_set_drvdata(pdev, NULL); + msdc_deinit_hw(host); + +#if 0 + tasklet_kill(&host->card_tasklet); +#else + cancel_delayed_work_sync(&host->card_delaywork); +#endif + + if (mem) + release_mem_region(mem->start, mem->end - mem->start + 1); + + mmc_free_host(mmc); + + return ret; +} + +/* 4 device share one driver, using "drvdata" to show difference */ +static int msdc_drv_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct msdc_host *host; + struct resource *mem; + + mmc = platform_get_drvdata(pdev); + BUG_ON(!mmc); + + host = mmc_priv(mmc); + BUG_ON(!host); + + ERR_MSG("removed !!!"); + + platform_set_drvdata(pdev, NULL); + mmc_remove_host(host->mmc); + msdc_deinit_hw(host); + +#if 0 + tasklet_kill(&host->card_tasklet); +#else + cancel_delayed_work_sync(&host->card_delaywork); +#endif + free_irq(host->irq, host); + + dma_free_coherent(NULL, MAX_GPD_NUM * sizeof(gpd_t), host->dma.gpd, host->dma.gpd_addr); + dma_free_coherent(NULL, MAX_BD_NUM * sizeof(bd_t), host->dma.bd, host->dma.bd_addr); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (mem) + release_mem_region(mem->start, mem->end - mem->start + 1); + + mmc_free_host(host->mmc); + + return 0; +} + +/* Fix me: Power Flow */ +#ifdef CONFIG_PM +static int msdc_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + int ret = 0; + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct msdc_host *host = mmc_priv(mmc); + + if (mmc && state.event == PM_EVENT_SUSPEND && (host->hw->flags & MSDC_SYS_SUSPEND)) { /* will set for card */ + msdc_pm(state, (void*)host); + } + + return ret; +} + +static int msdc_drv_resume(struct platform_device *pdev) +{ + int ret = 0; + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct msdc_host *host = mmc_priv(mmc); + struct pm_message state; + + state.event = PM_EVENT_RESUME; + if (mmc && (host->hw->flags & MSDC_SYS_SUSPEND)) {/* will set for card */ + msdc_pm(state, (void*)host); + } + + /* This mean WIFI not controller by PM */ + + return ret; +} +#endif + +static const struct of_device_id mt7620_sdhci_match[] = { + { .compatible = "ralink,mt7620-sdhci" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt7620_sdhci_match); + +static struct platform_driver mt_msdc_driver = { + .probe = msdc_drv_probe, + .remove = msdc_drv_remove, +#ifdef CONFIG_PM + .suspend = msdc_drv_suspend, + .resume = msdc_drv_resume, +#endif + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = mt7620_sdhci_match, + }, +}; + +/*--------------------------------------------------------------------------*/ +/* module init/exit */ +/*--------------------------------------------------------------------------*/ +static int __init mt_msdc_init(void) +{ + int ret; +/* +++ by chhung */ + u32 reg; + +#if defined (CONFIG_MTD_ANY_RALINK) + extern int ra_check_flash_type(void); + if(ra_check_flash_type() == 2) { /* NAND */ + printk("%s: !!!!! SDXC Module Initialize Fail !!!!!", __func__); + return 0; + } +#endif + printk("MTK MSDC device init.\n"); + mtk_sd_device.dev.platform_data = &msdc0_hw; +if (ralink_soc == MT762X_SOC_MT7620A || ralink_soc == MT762X_SOC_MT7621AT) { +//#if defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) + reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60)) & ~(0x3<<18); +//#if defined (CONFIG_RALINK_MT7620) + if (ralink_soc == MT762X_SOC_MT7620A) + reg |= 0x1<<18; +//#endif +} else { +//#elif defined (CONFIG_RALINK_MT7628) + /* TODO: maybe omitted when RAether already toggle AGPIO_CFG */ + reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x3c)); + reg |= 0x1e << 16; + sdr_write32((volatile u32*)(RALINK_SYSCTL_BASE + 0x3c), reg); + + reg = sdr_read32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60)) & ~(0x3<<10); +#if defined (CONFIG_MTK_MMC_EMMC_8BIT) + reg |= 0x3<<26 | 0x3<<28 | 0x3<<30; + msdc0_hw.data_pins = 8, +#endif +//#endif +} + sdr_write32((volatile u32*)(RALINK_SYSCTL_BASE + 0x60), reg); + //platform_device_register(&mtk_sd_device); +/* end of +++ */ + + ret = platform_driver_register(&mt_msdc_driver); + if (ret) { + printk(KERN_ERR DRV_NAME ": Can't register driver"); + return ret; + } + printk(KERN_INFO DRV_NAME ": MediaTek MT6575 MSDC Driver\n"); + +#if defined (MT6575_SD_DEBUG) + msdc_debug_proc_init(); +#endif + return 0; +} + +static void __exit mt_msdc_exit(void) +{ +// platform_device_unregister(&mtk_sd_device); + platform_driver_unregister(&mt_msdc_driver); +} + +module_init(mt_msdc_init); +module_exit(mt_msdc_exit); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek MT6575 SD/MMC Card Driver"); +MODULE_AUTHOR("Infinity Chen <infinity.chen@mediatek.com>"); + +EXPORT_SYMBOL(msdc_6575_host); diff --git a/drivers/staging/mt7621-pci/Makefile b/drivers/staging/mt7621-pci/Makefile new file mode 100644 index 000000000000..607b84bedcc3 --- /dev/null +++ b/drivers/staging/mt7621-pci/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SOC_MT7621) += pci-mt7621.o diff --git a/drivers/staging/mt7621-pci/TODO b/drivers/staging/mt7621-pci/TODO new file mode 100644 index 000000000000..cf30f629b9fd --- /dev/null +++ b/drivers/staging/mt7621-pci/TODO @@ -0,0 +1,12 @@ + +- general code review and cleanup +- can this be converted to not require PCI_DRIVERS_LEGACY ?? + The irq returned by pcibios_map_irq is a "hwirq" (hardware irq number) + and pci_assign_irq() assigns this directly to dev->irq, which + expects a "virq" (virtual irq number). These numbers are different + on MIPS. There is a gross hack to make it work on one + specific platform, so it can be tested. +- Should this be merged with arch/mips/pci/pci-mt7620.c ?? +- ensure device-tree requirements are documented + +Cc: NeilBrown <neil@brown.name> diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c new file mode 100644 index 000000000000..1fa41eb8a87f --- /dev/null +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -0,0 +1,840 @@ +/************************************************************************** + * + * BRIEF MODULE DESCRIPTION + * PCI init for Ralink RT2880 solution + * + * Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw) + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * + ************************************************************************** + * May 2007 Bruce Chang + * Initial Release + * + * May 2009 Bruce Chang + * support RT2880/RT3883 PCIe + * + * May 2011 Bruce Chang + * support RT6855/MT7620 PCIe + * + ************************************************************************** + */ + +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <asm/pci.h> +#include <asm/io.h> +#include <asm/mips-cm.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_pci.h> +#include <linux/platform_device.h> + +#include <ralink_regs.h> + +extern void pcie_phy_init(void); +extern void chk_phy_pll(void); + +/* + * These functions and structures provide the BIOS scan and mapping of the PCI + * devices. + */ + +#define CONFIG_PCIE_PORT0 +#define CONFIG_PCIE_PORT1 +#define CONFIG_PCIE_PORT2 +#define RALINK_PCIE0_CLK_EN (1<<24) +#define RALINK_PCIE1_CLK_EN (1<<25) +#define RALINK_PCIE2_CLK_EN (1<<26) + +#define RALINK_PCI_CONFIG_ADDR 0x20 +#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG 0x24 +#define SURFBOARDINT_PCIE0 11 /* PCIE0 */ +#define RALINK_INT_PCIE0 SURFBOARDINT_PCIE0 +#define RALINK_INT_PCIE1 SURFBOARDINT_PCIE1 +#define RALINK_INT_PCIE2 SURFBOARDINT_PCIE2 +#define SURFBOARDINT_PCIE1 31 /* PCIE1 */ +#define SURFBOARDINT_PCIE2 32 /* PCIE2 */ +#define RALINK_PCI_MEMBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x0028) +#define RALINK_PCI_IOBASE *(volatile u32 *)(RALINK_PCI_BASE + 0x002C) +#define RALINK_PCIE0_RST (1<<24) +#define RALINK_PCIE1_RST (1<<25) +#define RALINK_PCIE2_RST (1<<26) +#define RALINK_SYSCTL_BASE 0xBE000000 + +#define RALINK_PCI_PCICFG_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x0000) +#define RALINK_PCI_PCIMSK_ADDR *(volatile u32 *)(RALINK_PCI_BASE + 0x000C) +#define RALINK_PCI_BASE 0xBE140000 + +#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000) +#define RT6855_PCIE0_OFFSET 0x2000 +#define RT6855_PCIE1_OFFSET 0x3000 +#define RT6855_PCIE2_OFFSET 0x4000 + +#define RALINK_PCI0_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0010) +#define RALINK_PCI0_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0018) +#define RALINK_PCI0_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0030) +#define RALINK_PCI0_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0034) +#define RALINK_PCI0_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0038) +#define RALINK_PCI0_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0050) +#define RALINK_PCI0_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0060) +#define RALINK_PCI0_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0064) + +#define RALINK_PCI1_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0010) +#define RALINK_PCI1_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0018) +#define RALINK_PCI1_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0030) +#define RALINK_PCI1_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0034) +#define RALINK_PCI1_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0038) +#define RALINK_PCI1_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0050) +#define RALINK_PCI1_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0060) +#define RALINK_PCI1_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0064) + +#define RALINK_PCI2_BAR0SETUP_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0010) +#define RALINK_PCI2_IMBASEBAR0_ADDR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0018) +#define RALINK_PCI2_ID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0030) +#define RALINK_PCI2_CLASS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0034) +#define RALINK_PCI2_SUBID *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0038) +#define RALINK_PCI2_STATUS *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0050) +#define RALINK_PCI2_DERR *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0060) +#define RALINK_PCI2_ECRC *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0064) + +#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000) +#define RALINK_PCIEPHY_P2_CTL_OFFSET (RALINK_PCI_BASE + 0xA000) + + +#define MV_WRITE(ofs, data) \ + *(volatile u32 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le32(data) +#define MV_READ(ofs, data) \ + *(data) = le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs))) +#define MV_READ_DATA(ofs) \ + le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs))) + +#define MV_WRITE_16(ofs, data) \ + *(volatile u16 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le16(data) +#define MV_READ_16(ofs, data) \ + *(data) = le16_to_cpu(*(volatile u16 *)(RALINK_PCI_BASE+(ofs))) + +#define MV_WRITE_8(ofs, data) \ + *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) = data +#define MV_READ_8(ofs, data) \ + *(data) = *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) + + + +#define RALINK_PCI_MM_MAP_BASE 0x60000000 +#define RALINK_PCI_IO_MAP_BASE 0x1e160000 + +#define RALINK_SYSTEM_CONTROL_BASE 0xbe000000 +#define GPIO_PERST +#define ASSERT_SYSRST_PCIE(val) do { \ + if (*(unsigned int *)(0xbe00000c) == 0x00030101) \ + RALINK_RSTCTRL |= val; \ + else \ + RALINK_RSTCTRL &= ~val; \ + } while(0) +#define DEASSERT_SYSRST_PCIE(val) do { \ + if (*(unsigned int *)(0xbe00000c) == 0x00030101) \ + RALINK_RSTCTRL &= ~val; \ + else \ + RALINK_RSTCTRL |= val; \ + } while(0) +#define RALINK_SYSCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x14) +#define RALINK_CLKCFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x30) +#define RALINK_RSTCTRL *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x34) +#define RALINK_GPIOMODE *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x60) +#define RALINK_PCIE_CLK_GEN *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x7c) +#define RALINK_PCIE_CLK_GEN1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x80) +#define PPLL_CFG1 *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x9c) +#define PPLL_DRV *(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0xa0) +//RALINK_SYSCFG1 bit +#define RALINK_PCI_HOST_MODE_EN (1<<7) +#define RALINK_PCIE_RC_MODE_EN (1<<8) +//RALINK_RSTCTRL bit +#define RALINK_PCIE_RST (1<<23) +#define RALINK_PCI_RST (1<<24) +//RALINK_CLKCFG1 bit +#define RALINK_PCI_CLK_EN (1<<19) +#define RALINK_PCIE_CLK_EN (1<<21) +//RALINK_GPIOMODE bit +#define PCI_SLOTx2 (1<<11) +#define PCI_SLOTx1 (2<<11) +//MTK PCIE PLL bit +#define PDRV_SW_SET (1<<31) +#define LC_CKDRVPD_ (1<<19) + +#define MEMORY_BASE 0x0 +static int pcie_link_status = 0; + +#define PCI_ACCESS_READ_1 0 +#define PCI_ACCESS_READ_2 1 +#define PCI_ACCESS_READ_4 2 +#define PCI_ACCESS_WRITE_1 3 +#define PCI_ACCESS_WRITE_2 4 +#define PCI_ACCESS_WRITE_4 5 + +static int config_access(unsigned char access_type, struct pci_bus *bus, + unsigned int devfn, unsigned int where, u32 * data) +{ + unsigned int slot = PCI_SLOT(devfn); + u8 func = PCI_FUNC(devfn); + uint32_t address_reg, data_reg; + unsigned int address; + + address_reg = RALINK_PCI_CONFIG_ADDR; + data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; + + address = (((where&0xF00)>>8)<<24) |(bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000; + MV_WRITE(address_reg, address); + + switch(access_type) { + case PCI_ACCESS_WRITE_1: + MV_WRITE_8(data_reg+(where&0x3), *data); + break; + case PCI_ACCESS_WRITE_2: + MV_WRITE_16(data_reg+(where&0x3), *data); + break; + case PCI_ACCESS_WRITE_4: + MV_WRITE(data_reg, *data); + break; + case PCI_ACCESS_READ_1: + MV_READ_8( data_reg+(where&0x3), data); + break; + case PCI_ACCESS_READ_2: + MV_READ_16(data_reg+(where&0x3), data); + break; + case PCI_ACCESS_READ_4: + MV_READ(data_reg, data); + break; + default: + printk("no specify access type\n"); + break; + } + return 0; +} + +static int +read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val) +{ + return config_access(PCI_ACCESS_READ_1, bus, devfn, (unsigned int)where, (u32 *)val); +} + +static int +read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val) +{ + return config_access(PCI_ACCESS_READ_2, bus, devfn, (unsigned int)where, (u32 *)val); +} + +static int +read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val) +{ + return config_access(PCI_ACCESS_READ_4, bus, devfn, (unsigned int)where, (u32 *)val); +} + +static int +write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val) +{ + if (config_access(PCI_ACCESS_WRITE_1, bus, devfn, (unsigned int)where, (u32 *)&val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int +write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val) +{ + if (config_access(PCI_ACCESS_WRITE_2, bus, devfn, where, (u32 *)&val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + +static int +write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) +{ + if (config_access(PCI_ACCESS_WRITE_4, bus, devfn, where, &val)) + return -1; + + return PCIBIOS_SUCCESSFUL; +} + + +static int +pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) +{ + switch (size) { + case 1: + return read_config_byte(bus, devfn, where, (u8 *) val); + case 2: + return read_config_word(bus, devfn, where, (u16 *) val); + default: + return read_config_dword(bus, devfn, where, val); + } +} + +static int +pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) +{ + switch (size) { + case 1: + return write_config_byte(bus, devfn, where, (u8) val); + case 2: + return write_config_word(bus, devfn, where, (u16) val); + default: + return write_config_dword(bus, devfn, where, val); + } +} + +struct pci_ops mt7621_pci_ops= { + .read = pci_config_read, + .write = pci_config_write, +}; + +static struct resource mt7621_res_pci_mem1 = { + .name = "PCI MEM1", + .start = RALINK_PCI_MM_MAP_BASE, + .end = (u32)((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)), + .flags = IORESOURCE_MEM, +}; +static struct resource mt7621_res_pci_io1 = { + .name = "PCI I/O1", + .start = RALINK_PCI_IO_MAP_BASE, + .end = (u32)((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)), + .flags = IORESOURCE_IO, +}; + +static struct pci_controller mt7621_controller = { + .pci_ops = &mt7621_pci_ops, + .mem_resource = &mt7621_res_pci_mem1, + .io_resource = &mt7621_res_pci_io1, + .mem_offset = 0x00000000UL, + .io_offset = 0x00000000UL, + .io_map_base = 0xa0000000, +}; + +static void +read_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long *val) +{ + unsigned int address_reg, data_reg, address; + + address_reg = RALINK_PCI_CONFIG_ADDR; + data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; + address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ; + MV_WRITE(address_reg, address); + MV_READ(data_reg, val); + return; +} + +static void +write_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long val) +{ + unsigned int address_reg, data_reg, address; + + address_reg = RALINK_PCI_CONFIG_ADDR; + data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; + address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ; + MV_WRITE(address_reg, address); + MV_WRITE(data_reg, val); + return; +} + + +int +pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + u16 cmd; + u32 val; + int irq = 0; + + if ((dev->bus->number == 0) && (slot == 0)) { + write_config(0, 0, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); + read_config(0, 0, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); + printk("BAR0 at slot 0 = %x\n", val); + printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); + } else if((dev->bus->number == 0) && (slot == 0x1)) { + write_config(0, 1, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); + read_config(0, 1, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); + printk("BAR0 at slot 1 = %x\n", val); + printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); + } else if((dev->bus->number == 0) && (slot == 0x2)) { + write_config(0, 2, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); + read_config(0, 2, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); + printk("BAR0 at slot 2 = %x\n", val); + printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); + } else if ((dev->bus->number == 1) && (slot == 0x0)) { + switch (pcie_link_status) { + case 2: + case 6: + irq = RALINK_INT_PCIE1; + break; + case 4: + irq = RALINK_INT_PCIE2; + break; + default: + irq = RALINK_INT_PCIE0; + } + printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); + } else if ((dev->bus->number == 2) && (slot == 0x0)) { + switch (pcie_link_status) { + case 5: + case 6: + irq = RALINK_INT_PCIE2; + break; + default: + irq = RALINK_INT_PCIE1; + } + printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); + } else if ((dev->bus->number == 2) && (slot == 0x1)) { + switch (pcie_link_status) { + case 5: + case 6: + irq = RALINK_INT_PCIE2; + break; + default: + irq = RALINK_INT_PCIE1; + } + printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); + } else if ((dev->bus->number ==3) && (slot == 0x0)) { + irq = RALINK_INT_PCIE2; + printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); + } else if ((dev->bus->number ==3) && (slot == 0x1)) { + irq = RALINK_INT_PCIE2; + printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); + } else if ((dev->bus->number ==3) && (slot == 0x2)) { + irq = RALINK_INT_PCIE2; + printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); + } else { + printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); + return 0; + } + + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14); //configure cache line size 0x14 + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF); //configure latency timer 0x10 + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +#ifdef CONFIG_DTB_GNUBEE1 + /* + * 'irq' here is a hwirq, but a virq is needed. Until we know how and where + * to convert one to the other, we have this hack for the GNUBEE1 + */ + return irq == 11 ? 22 : irq; +#else + return irq; +#endif +} + +void +set_pcie_phy(u32 *addr, int start_b, int bits, int val) +{ +// printk("0x%p:", addr); +// printk(" %x", *addr); + *(unsigned int *)(addr) &= ~(((1<<bits) - 1)<<start_b); + *(unsigned int *)(addr) |= val << start_b; +// printk(" -> %x\n", *addr); +} + +void +bypass_pipe_rst(void) +{ +#if defined (CONFIG_PCIE_PORT0) + /* PCIe Port 0 */ + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4] +#endif +#if defined (CONFIG_PCIE_PORT1) + /* PCIe Port 1 */ + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 12, 1, 0x01); // rg_pe1_pipe_rst_b + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4] +#endif +#if defined (CONFIG_PCIE_PORT2) + /* PCIe Port 2 */ + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 12, 1, 0x01); // rg_pe1_pipe_rst_b + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 4, 1, 0x01); // rg_pe1_pipe_cmd_frc[4] +#endif +} + +void +set_phy_for_ssc(void) +{ + unsigned long reg = (*(volatile u32 *)(RALINK_SYSCTL_BASE + 0x10)); + + reg = (reg >> 6) & 0x7; +#if defined (CONFIG_PCIE_PORT0) || defined (CONFIG_PCIE_PORT1) + /* Set PCIe Port0 & Port1 PHY to disable SSC */ + /* Debug Xtal Type */ + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 1 enable control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x00); // rg_pe1_phy_en //Port 1 disable + if(reg <= 5 && reg >= 3) { // 40MHz Xtal + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) + printk("***** Xtal 40MHz *****\n"); + } else { // 25MHz | 20MHz Xtal + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) + if (reg >= 6) { + printk("***** Xtal 25MHz *****\n"); + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode) + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial + } else { + printk("***** Xtal 20MHz *****\n"); + } + } + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN + if(reg <= 5 && reg >= 3) { // 40MHz Xtal + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv + } + /* Enable PHY and disable force mode */ + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 5, 1, 0x01); // rg_pe1_phy_en //Port 1 enable + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 1 disable control +#endif +#if defined (CONFIG_PCIE_PORT2) + /* Set PCIe Port2 PHY to disable SSC */ + /* Debug Xtal Type */ + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 8, 1, 0x01); // rg_pe1_frc_h_xtal_type + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400), 9, 2, 0x00); // rg_pe1_h_xtal_type + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x01); // rg_pe1_frc_phy_en //Force Port 0 enable control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x00); // rg_pe1_phy_en //Port 0 disable + if(reg <= 5 && reg >= 3) { // 40MHz Xtal + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x01); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) + } else { // 25MHz | 20MHz Xtal + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 6, 2, 0x00); // RG_PE1_H_PLL_PREDIV //Pre-divider ratio (for host mode) + if (reg >= 6) { // 25MHz Xtal + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4bc), 4, 2, 0x01); // RG_PE1_H_PLL_FBKSEL //Feedback clock select + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x49c), 0,31, 0x18000000); // RG_PE1_H_LCDDS_PCW_NCPO //DDS NCPO PCW (for host mode) + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a4), 0,16, 0x18d); // RG_PE1_H_LCDDS_SSC_PRD //DDS SSC dither period control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 0,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA //DDS SSC dither amplitude control + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 16,12, 0x4a); // RG_PE1_H_LCDDS_SSC_DELTA1 //DDS SSC dither amplitude control for initial + } + } + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a0), 5, 1, 0x01); // RG_PE1_LCDDS_CLK_PH_INV //DDS clock inversion + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 22, 2, 0x02); // RG_PE1_H_PLL_BC + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 18, 4, 0x06); // RG_PE1_H_PLL_BP + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 12, 4, 0x02); // RG_PE1_H_PLL_IR + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 8, 4, 0x01); // RG_PE1_H_PLL_IC + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4ac), 16, 3, 0x00); // RG_PE1_H_PLL_BR + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 1, 3, 0x02); // RG_PE1_PLL_DIVEN + if(reg <= 5 && reg >= 3) { // 40MHz Xtal + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 6, 2, 0x01); // rg_pe1_mstckdiv //value of da_pe1_mstckdiv when force mode enable + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414), 5, 1, 0x01); // rg_pe1_frc_mstckdiv //force mode enable of da_pe1_mstckdiv + } + /* Enable PHY and disable force mode */ + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 5, 1, 0x01); // rg_pe1_phy_en //Port 0 enable + set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000), 4, 1, 0x00); // rg_pe1_frc_phy_en //Force Port 0 disable control +#endif +} + +void setup_cm_memory_region(struct resource *mem_resource) +{ + resource_size_t mask; + if (mips_cps_numiocu(0)) { + /* FIXME: hardware doesn't accept mask values with 1s after + 0s (e.g. 0xffef), so it would be great to warn if that's + about to happen */ + mask = ~(mem_resource->end - mem_resource->start); + + write_gcr_reg1_base(mem_resource->start); + write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0); + printk("PCI coherence region base: 0x%08llx, mask/settings: 0x%08llx\n", + (unsigned long long)read_gcr_reg1_base(), + (unsigned long long)read_gcr_reg1_mask()); + } +} + +static int mt7621_pci_probe(struct platform_device *pdev) +{ + unsigned long val = 0; + + iomem_resource.start = 0; + iomem_resource.end= ~0; + ioport_resource.start= 0; + ioport_resource.end = ~0; + +#if defined (CONFIG_PCIE_PORT0) + val = RALINK_PCIE0_RST; +#endif +#if defined (CONFIG_PCIE_PORT1) + val |= RALINK_PCIE1_RST; +#endif +#if defined (CONFIG_PCIE_PORT2) + val |= RALINK_PCIE2_RST; +#endif + ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST | RALINK_PCIE1_RST | RALINK_PCIE2_RST); + printk("pull PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); +#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/ + *(unsigned int *)(0xbe000060) &= ~(0x3<<10 | 0x3<<3); + *(unsigned int *)(0xbe000060) |= 0x1<<10 | 0x1<<3; + mdelay(100); + *(unsigned int *)(0xbe000600) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3) + mdelay(100); + *(unsigned int *)(0xbe000620) &= ~(0x1<<19 | 0x1<<8 | 0x1<<7); // clear DATA + + mdelay(100); +#else + *(unsigned int *)(0xbe000060) &= ~0x00000c00; +#endif +#if defined (CONFIG_PCIE_PORT0) + val = RALINK_PCIE0_RST; +#endif +#if defined (CONFIG_PCIE_PORT1) + val |= RALINK_PCIE1_RST; +#endif +#if defined (CONFIG_PCIE_PORT2) + val |= RALINK_PCIE2_RST; +#endif + DEASSERT_SYSRST_PCIE(val); + printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); + + if ((*(unsigned int *)(0xbe00000c)&0xFFFF) == 0x0101) // MT7621 E2 + bypass_pipe_rst(); + set_phy_for_ssc(); + printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); + +#if defined (CONFIG_PCIE_PORT0) + read_config(0, 0, 0, 0x70c, &val); + printk("Port 0 N_FTS = %x\n", (unsigned int)val); +#endif +#if defined (CONFIG_PCIE_PORT1) + read_config(0, 1, 0, 0x70c, &val); + printk("Port 1 N_FTS = %x\n", (unsigned int)val); +#endif +#if defined (CONFIG_PCIE_PORT2) + read_config(0, 2, 0, 0x70c, &val); + printk("Port 2 N_FTS = %x\n", (unsigned int)val); +#endif + + RALINK_RSTCTRL = (RALINK_RSTCTRL | RALINK_PCIE_RST); + RALINK_SYSCFG1 &= ~(0x30); + RALINK_SYSCFG1 |= (2<<4); + RALINK_PCIE_CLK_GEN &= 0x7fffffff; + RALINK_PCIE_CLK_GEN1 &= 0x80ffffff; + RALINK_PCIE_CLK_GEN1 |= 0xa << 24; + RALINK_PCIE_CLK_GEN |= 0x80000000; + mdelay(50); + RALINK_RSTCTRL = (RALINK_RSTCTRL & ~RALINK_PCIE_RST); + + +#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/ + *(unsigned int *)(0xbe000620) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // set DATA + mdelay(100); +#else + RALINK_PCI_PCICFG_ADDR &= ~(1<<1); //de-assert PERST +#endif + mdelay(500); + + + mdelay(500); +#if defined (CONFIG_PCIE_PORT0) + if(( RALINK_PCI0_STATUS & 0x1) == 0) + { + printk("PCIE0 no card, disable it(RST&CLK)\n"); + ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST); + RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE0_CLK_EN); + pcie_link_status &= ~(1<<0); + } else { + pcie_link_status |= 1<<0; + RALINK_PCI_PCIMSK_ADDR |= (1<<20); // enable pcie1 interrupt + } +#endif +#if defined (CONFIG_PCIE_PORT1) + if(( RALINK_PCI1_STATUS & 0x1) == 0) + { + printk("PCIE1 no card, disable it(RST&CLK)\n"); + ASSERT_SYSRST_PCIE(RALINK_PCIE1_RST); + RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE1_CLK_EN); + pcie_link_status &= ~(1<<1); + } else { + pcie_link_status |= 1<<1; + RALINK_PCI_PCIMSK_ADDR |= (1<<21); // enable pcie1 interrupt + } +#endif +#if defined (CONFIG_PCIE_PORT2) + if (( RALINK_PCI2_STATUS & 0x1) == 0) { + printk("PCIE2 no card, disable it(RST&CLK)\n"); + ASSERT_SYSRST_PCIE(RALINK_PCIE2_RST); + RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE2_CLK_EN); + pcie_link_status &= ~(1<<2); + } else { + pcie_link_status |= 1<<2; + RALINK_PCI_PCIMSK_ADDR |= (1<<22); // enable pcie2 interrupt + } +#endif + if (pcie_link_status == 0) + return 0; + +/* +pcie(2/1/0) link status pcie2_num pcie1_num pcie0_num +3'b000 x x x +3'b001 x x 0 +3'b010 x 0 x +3'b011 x 1 0 +3'b100 0 x x +3'b101 1 x 0 +3'b110 1 0 x +3'b111 2 1 0 +*/ + switch(pcie_link_status) { + case 2: + RALINK_PCI_PCICFG_ADDR &= ~0x00ff0000; + RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0 + RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1 + break; + case 4: + RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; + RALINK_PCI_PCICFG_ADDR |= 0x1 << 16; //port0 + RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1 + RALINK_PCI_PCICFG_ADDR |= 0x0 << 24; //port2 + break; + case 5: + RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; + RALINK_PCI_PCICFG_ADDR |= 0x0 << 16; //port0 + RALINK_PCI_PCICFG_ADDR |= 0x2 << 20; //port1 + RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2 + break; + case 6: + RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; + RALINK_PCI_PCICFG_ADDR |= 0x2 << 16; //port0 + RALINK_PCI_PCICFG_ADDR |= 0x0 << 20; //port1 + RALINK_PCI_PCICFG_ADDR |= 0x1 << 24; //port2 + break; + } + printk(" -> %x\n", RALINK_PCI_PCICFG_ADDR); + //printk(" RALINK_PCI_ARBCTL = %x\n", RALINK_PCI_ARBCTL); + +/* + ioport_resource.start = mt7621_res_pci_io1.start; + ioport_resource.end = mt7621_res_pci_io1.end; +*/ + + RALINK_PCI_MEMBASE = 0xffffffff; //RALINK_PCI_MM_MAP_BASE; + RALINK_PCI_IOBASE = RALINK_PCI_IO_MAP_BASE; + +#if defined (CONFIG_PCIE_PORT0) + //PCIe0 + if((pcie_link_status & 0x1) != 0) { + RALINK_PCI0_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE + RALINK_PCI0_IMBASEBAR0_ADDR = MEMORY_BASE; + RALINK_PCI0_CLASS = 0x06040001; + printk("PCIE0 enabled\n"); + } +#endif +#if defined (CONFIG_PCIE_PORT1) + //PCIe1 + if ((pcie_link_status & 0x2) != 0) { + RALINK_PCI1_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE + RALINK_PCI1_IMBASEBAR0_ADDR = MEMORY_BASE; + RALINK_PCI1_CLASS = 0x06040001; + printk("PCIE1 enabled\n"); + } +#endif +#if defined (CONFIG_PCIE_PORT2) + //PCIe2 + if ((pcie_link_status & 0x4) != 0) { + RALINK_PCI2_BAR0SETUP_ADDR = 0x7FFF0001; //open 7FFF:2G; ENABLE + RALINK_PCI2_IMBASEBAR0_ADDR = MEMORY_BASE; + RALINK_PCI2_CLASS = 0x06040001; + printk("PCIE2 enabled\n"); + } +#endif + + + switch(pcie_link_status) { + case 7: + read_config(0, 2, 0, 0x4, &val); + write_config(0, 2, 0, 0x4, val|0x4); + // write_config(0, 1, 0, 0x4, val|0x7); + read_config(0, 2, 0, 0x70c, &val); + val &= ~(0xff)<<8; + val |= 0x50<<8; + write_config(0, 2, 0, 0x70c, val); + case 3: + case 5: + case 6: + read_config(0, 1, 0, 0x4, &val); + write_config(0, 1, 0, 0x4, val|0x4); + // write_config(0, 1, 0, 0x4, val|0x7); + read_config(0, 1, 0, 0x70c, &val); + val &= ~(0xff)<<8; + val |= 0x50<<8; + write_config(0, 1, 0, 0x70c, val); + default: + read_config(0, 0, 0, 0x4, &val); + write_config(0, 0, 0, 0x4, val|0x4); //bus master enable + // write_config(0, 0, 0, 0x4, val|0x7); //bus master enable + read_config(0, 0, 0, 0x70c, &val); + val &= ~(0xff)<<8; + val |= 0x50<<8; + write_config(0, 0, 0, 0x70c, val); + } + + pci_load_of_ranges(&mt7621_controller, pdev->dev.of_node); + setup_cm_memory_region(mt7621_controller.mem_resource); + register_pci_controller(&mt7621_controller); + return 0; + +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static const struct of_device_id mt7621_pci_ids[] = { + { .compatible = "mediatek,mt7621-pci" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt7621_pci_ids); + +static struct platform_driver mt7621_pci_driver = { + .probe = mt7621_pci_probe, + .driver = { + .name = "mt7621-pci", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mt7621_pci_ids), + }, +}; + +static int __init mt7621_pci_init(void) +{ + return platform_driver_register(&mt7621_pci_driver); +} + +arch_initcall(mt7621_pci_init); diff --git a/drivers/staging/mt7621-pinctrl/Kconfig b/drivers/staging/mt7621-pinctrl/Kconfig new file mode 100644 index 000000000000..37cf9c3273be --- /dev/null +++ b/drivers/staging/mt7621-pinctrl/Kconfig @@ -0,0 +1,4 @@ +config PINCTRL_RT2880 + bool "RT2800 pinctrl driver for RALINK/Mediatek SOCs" + depends on RALINK + select PINMUX diff --git a/drivers/staging/mt7621-pinctrl/Makefile b/drivers/staging/mt7621-pinctrl/Makefile new file mode 100644 index 000000000000..856102137a1e --- /dev/null +++ b/drivers/staging/mt7621-pinctrl/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_PINCTRL_RT2880) += pinctrl-rt2880.o + +ccflags-y += -I$(srctree)/drivers/pinctrl diff --git a/drivers/staging/mt7621-pinctrl/TODO b/drivers/staging/mt7621-pinctrl/TODO new file mode 100644 index 000000000000..b2c235a16d5c --- /dev/null +++ b/drivers/staging/mt7621-pinctrl/TODO @@ -0,0 +1,6 @@ + +- general code review and cleanup +- should probably be always selected by 'config RALINK' +- ensure device-tree requirements are documented + +Cc: NeilBrown <neil@brown.name> diff --git a/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c new file mode 100644 index 000000000000..3d2d1c2a006f --- /dev/null +++ b/drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c @@ -0,0 +1,472 @@ +/* + * linux/drivers/pinctrl/pinctrl-rt2880.c + * + * 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 + * publishhed by the Free Software Foundation. + * + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/machine.h> + +#include <asm/mach-ralink/ralink_regs.h> +#include <asm/mach-ralink/pinmux.h> +#include <asm/mach-ralink/mt7620.h> + +#include "core.h" + +#define SYSC_REG_GPIO_MODE 0x60 +#define SYSC_REG_GPIO_MODE2 0x64 + +struct rt2880_priv { + struct device *dev; + + struct pinctrl_pin_desc *pads; + struct pinctrl_desc *desc; + + struct rt2880_pmx_func **func; + int func_count; + + struct rt2880_pmx_group *groups; + const char **group_names; + int group_count; + + uint8_t *gpio; + int max_pins; +}; + +static int rt2880_get_group_count(struct pinctrl_dev *pctrldev) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + + return p->group_count; +} + +static const char *rt2880_get_group_name(struct pinctrl_dev *pctrldev, + unsigned group) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + + if (group >= p->group_count) + return NULL; + + return p->group_names[group]; +} + +static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev, + unsigned group, + const unsigned **pins, + unsigned *num_pins) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + + if (group >= p->group_count) + return -EINVAL; + + *pins = p->groups[group].func[0].pins; + *num_pins = p->groups[group].func[0].pin_count; + + return 0; +} + +static void rt2880_pinctrl_dt_free_map(struct pinctrl_dev *pctrldev, + struct pinctrl_map *map, unsigned num_maps) +{ + int i; + + for (i = 0; i < num_maps; i++) + if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN || + map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) + kfree(map[i].data.configs.configs); + kfree(map); +} + +static void rt2880_pinctrl_pin_dbg_show(struct pinctrl_dev *pctrldev, + struct seq_file *s, + unsigned offset) +{ + seq_printf(s, "ralink pio"); +} + +static void rt2880_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctrldev, + struct device_node *np, + struct pinctrl_map **map) +{ + const char *function; + int func = of_property_read_string(np, "ralink,function", &function); + int grps = of_property_count_strings(np, "ralink,group"); + int i; + + if (func || !grps) + return; + + for (i = 0; i < grps; i++) { + const char *group; + + of_property_read_string_index(np, "ralink,group", i, &group); + + (*map)->type = PIN_MAP_TYPE_MUX_GROUP; + (*map)->name = function; + (*map)->data.mux.group = group; + (*map)->data.mux.function = function; + (*map)++; + } +} + +static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) +{ + int max_maps = 0; + struct pinctrl_map *tmp; + struct device_node *np; + + for_each_child_of_node(np_config, np) { + int ret = of_property_count_strings(np, "ralink,group"); + + if (ret >= 0) + max_maps += ret; + } + + if (!max_maps) + return max_maps; + + *map = kzalloc(max_maps * sizeof(struct pinctrl_map), GFP_KERNEL); + if (!*map) + return -ENOMEM; + + tmp = *map; + + for_each_child_of_node(np_config, np) + rt2880_pinctrl_dt_subnode_to_map(pctrldev, np, &tmp); + *num_maps = max_maps; + + return 0; +} + +static const struct pinctrl_ops rt2880_pctrl_ops = { + .get_groups_count = rt2880_get_group_count, + .get_group_name = rt2880_get_group_name, + .get_group_pins = rt2880_get_group_pins, + .pin_dbg_show = rt2880_pinctrl_pin_dbg_show, + .dt_node_to_map = rt2880_pinctrl_dt_node_to_map, + .dt_free_map = rt2880_pinctrl_dt_free_map, +}; + +static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + + return p->func_count; +} + +static const char *rt2880_pmx_func_name(struct pinctrl_dev *pctrldev, + unsigned func) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + + return p->func[func]->name; +} + +static int rt2880_pmx_group_get_groups(struct pinctrl_dev *pctrldev, + unsigned func, + const char * const **groups, + unsigned * const num_groups) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + + if (p->func[func]->group_count == 1) + *groups = &p->group_names[p->func[func]->groups[0]]; + else + *groups = p->group_names; + + *num_groups = p->func[func]->group_count; + + return 0; +} + +static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev, + unsigned func, + unsigned group) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + u32 mode = 0; + u32 reg = SYSC_REG_GPIO_MODE; + int i; + int shift; + + /* dont allow double use */ + if (p->groups[group].enabled) { + dev_err(p->dev, "%s is already enabled\n", p->groups[group].name); + return -EBUSY; + } + + p->groups[group].enabled = 1; + p->func[func]->enabled = 1; + + shift = p->groups[group].shift; + if (shift >= 32) { + shift -= 32; + reg = SYSC_REG_GPIO_MODE2; + } + mode = rt_sysc_r32(reg); + mode &= ~(p->groups[group].mask << shift); + + /* mark the pins as gpio */ + for (i = 0; i < p->groups[group].func[0].pin_count; i++) + p->gpio[p->groups[group].func[0].pins[i]] = 1; + + /* function 0 is gpio and needs special handling */ + if (func == 0) { + mode |= p->groups[group].gpio << shift; + } else { + for (i = 0; i < p->func[func]->pin_count; i++) + p->gpio[p->func[func]->pins[i]] = 0; + mode |= p->func[func]->value << shift; + } + rt_sysc_w32(mode, reg); + + return 0; +} + +static int rt2880_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev, + struct pinctrl_gpio_range *range, + unsigned pin) +{ + struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); + + if (!p->gpio[pin]) { + dev_err(p->dev, "pin %d is not set to gpio mux\n", pin); + return -EINVAL; + } + + return 0; +} + +static const struct pinmux_ops rt2880_pmx_group_ops = { + .get_functions_count = rt2880_pmx_func_count, + .get_function_name = rt2880_pmx_func_name, + .get_function_groups = rt2880_pmx_group_get_groups, + .set_mux = rt2880_pmx_group_enable, + .gpio_request_enable = rt2880_pmx_group_gpio_request_enable, +}; + +static struct pinctrl_desc rt2880_pctrl_desc = { + .owner = THIS_MODULE, + .name = "rt2880-pinmux", + .pctlops = &rt2880_pctrl_ops, + .pmxops = &rt2880_pmx_group_ops, +}; + +static struct rt2880_pmx_func gpio_func = { + .name = "gpio", +}; + +static int rt2880_pinmux_index(struct rt2880_priv *p) +{ + struct rt2880_pmx_func **f; + struct rt2880_pmx_group *mux = p->groups; + int i, j, c = 0; + + /* count the mux functions */ + while (mux->name) { + p->group_count++; + mux++; + } + + /* allocate the group names array needed by the gpio function */ + p->group_names = devm_kzalloc(p->dev, sizeof(char *) * p->group_count, GFP_KERNEL); + if (!p->group_names) + return -1; + + for (i = 0; i < p->group_count; i++) { + p->group_names[i] = p->groups[i].name; + p->func_count += p->groups[i].func_count; + } + + /* we have a dummy function[0] for gpio */ + p->func_count++; + + /* allocate our function and group mapping index buffers */ + f = p->func = devm_kzalloc(p->dev, sizeof(struct rt2880_pmx_func) * p->func_count, GFP_KERNEL); + gpio_func.groups = devm_kzalloc(p->dev, sizeof(int) * p->group_count, GFP_KERNEL); + if (!f || !gpio_func.groups) + return -1; + + /* add a backpointer to the function so it knows its group */ + gpio_func.group_count = p->group_count; + for (i = 0; i < gpio_func.group_count; i++) + gpio_func.groups[i] = i; + + f[c] = &gpio_func; + c++; + + /* add remaining functions */ + for (i = 0; i < p->group_count; i++) { + for (j = 0; j < p->groups[i].func_count; j++) { + f[c] = &p->groups[i].func[j]; + f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL); + f[c]->groups[0] = i; + f[c]->group_count = 1; + c++; + } + } + return 0; +} + +static int rt2880_pinmux_pins(struct rt2880_priv *p) +{ + int i, j; + + /* loop over the functions and initialize the pins array. also work out the highest pin used */ + for (i = 0; i < p->func_count; i++) { + int pin; + + if (!p->func[i]->pin_count) + continue; + + p->func[i]->pins = devm_kzalloc(p->dev, sizeof(int) * p->func[i]->pin_count, GFP_KERNEL); + for (j = 0; j < p->func[i]->pin_count; j++) + p->func[i]->pins[j] = p->func[i]->pin_first + j; + + pin = p->func[i]->pin_first + p->func[i]->pin_count; + if (pin > p->max_pins) + p->max_pins = pin; + } + + /* the buffer that tells us which pins are gpio */ + p->gpio = devm_kzalloc(p->dev,sizeof(uint8_t) * p->max_pins, + GFP_KERNEL); + /* the pads needed to tell pinctrl about our pins */ + p->pads = devm_kzalloc(p->dev, + sizeof(struct pinctrl_pin_desc) * p->max_pins, + GFP_KERNEL); + if (!p->pads || !p->gpio ) { + dev_err(p->dev, "Failed to allocate gpio data\n"); + return -ENOMEM; + } + + memset(p->gpio, 1, sizeof(uint8_t) * p->max_pins); + for (i = 0; i < p->func_count; i++) { + if (!p->func[i]->pin_count) + continue; + + for (j = 0; j < p->func[i]->pin_count; j++) + p->gpio[p->func[i]->pins[j]] = 0; + } + + /* pin 0 is always a gpio */ + p->gpio[0] = 1; + + /* set the pads */ + for (i = 0; i < p->max_pins; i++) { + /* strlen("ioXY") + 1 = 5 */ + char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL); + + if (!name) { + dev_err(p->dev, "Failed to allocate pad name\n"); + return -ENOMEM; + } + snprintf(name, 5, "io%d", i); + p->pads[i].number = i; + p->pads[i].name = name; + } + p->desc->pins = p->pads; + p->desc->npins = p->max_pins; + + return 0; +} + +static int rt2880_pinmux_probe(struct platform_device *pdev) +{ + struct rt2880_priv *p; + struct pinctrl_dev *dev; + struct device_node *np; + + if (!rt2880_pinmux_data) + return -ENOSYS; + + /* setup the private data */ + p = devm_kzalloc(&pdev->dev, sizeof(struct rt2880_priv), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->dev = &pdev->dev; + p->desc = &rt2880_pctrl_desc; + p->groups = rt2880_pinmux_data; + platform_set_drvdata(pdev, p); + + /* init the device */ + if (rt2880_pinmux_index(p)) { + dev_err(&pdev->dev, "failed to load index\n"); + return -EINVAL; + } + if (rt2880_pinmux_pins(p)) { + dev_err(&pdev->dev, "failed to load pins\n"); + return -EINVAL; + } + dev = pinctrl_register(p->desc, &pdev->dev, p); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + /* finalize by adding gpio ranges for enables gpio controllers */ + for_each_compatible_node(np, NULL, "ralink,rt2880-gpio") { + const __be32 *ngpio, *gpiobase; + struct pinctrl_gpio_range *range; + char *name; + + if (!of_device_is_available(np)) + continue; + + ngpio = of_get_property(np, "ralink,num-gpios", NULL); + gpiobase = of_get_property(np, "ralink,gpio-base", NULL); + if (!ngpio || !gpiobase) { + dev_err(&pdev->dev, "failed to load chip info\n"); + return -EINVAL; + } + + range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL); + range->name = name = (char *) &range[1]; + sprintf(name, "pio"); + range->npins = __be32_to_cpu(*ngpio); + range->base = __be32_to_cpu(*gpiobase); + range->pin_base = range->base; + pinctrl_add_gpio_range(dev, range); + } + + return 0; +} + +static const struct of_device_id rt2880_pinmux_match[] = { + { .compatible = "ralink,rt2880-pinmux" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt2880_pinmux_match); + +static struct platform_driver rt2880_pinmux_driver = { + .probe = rt2880_pinmux_probe, + .driver = { + .name = "rt2880-pinmux", + .owner = THIS_MODULE, + .of_match_table = rt2880_pinmux_match, + }, +}; + +int __init rt2880_pinmux_init(void) +{ + return platform_driver_register(&rt2880_pinmux_driver); +} + +core_initcall_sync(rt2880_pinmux_init); diff --git a/drivers/staging/mt7621-spi/Kconfig b/drivers/staging/mt7621-spi/Kconfig new file mode 100644 index 000000000000..0b90f4cfa426 --- /dev/null +++ b/drivers/staging/mt7621-spi/Kconfig @@ -0,0 +1,6 @@ +config SPI_MT7621 + tristate "MediaTek MT7621 SPI Controller" + depends on RALINK + help + This selects a driver for the MediaTek MT7621 SPI Controller. + diff --git a/drivers/staging/mt7621-spi/Makefile b/drivers/staging/mt7621-spi/Makefile new file mode 100644 index 000000000000..3be508f63bac --- /dev/null +++ b/drivers/staging/mt7621-spi/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SPI_MT7621) += spi-mt7621.o diff --git a/drivers/staging/mt7621-spi/TODO b/drivers/staging/mt7621-spi/TODO new file mode 100644 index 000000000000..fdbc5002c32a --- /dev/null +++ b/drivers/staging/mt7621-spi/TODO @@ -0,0 +1,5 @@ + +- general code review and clean up +- ensure device-tree requirements are documented + +Cc: NeilBrown <neil@brown.name> diff --git a/drivers/staging/mt7621-spi/spi-mt7621.c b/drivers/staging/mt7621-spi/spi-mt7621.c new file mode 100644 index 000000000000..d95e0b32f1f0 --- /dev/null +++ b/drivers/staging/mt7621-spi/spi-mt7621.c @@ -0,0 +1,489 @@ +/* + * spi-mt7621.c -- MediaTek MT7621 SPI controller driver + * + * Copyright (C) 2011 Sergiy <piratfm@gmail.com> + * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> + * Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name> + * + * Some parts are based on spi-orion.c: + * Author: Shadi Ammouri <shadi@marvell.com> + * Copyright (C) 2007-2008 Marvell Ltd. + * + * 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 <linux/init.h> +#include <linux/module.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/reset.h> +#include <linux/spi/spi.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/swab.h> + +#include <ralink_regs.h> + +#define SPI_BPW_MASK(bits) BIT((bits) - 1) + +#define DRIVER_NAME "spi-mt7621" +/* in usec */ +#define RALINK_SPI_WAIT_MAX_LOOP 2000 + +/* SPISTAT register bit field */ +#define SPISTAT_BUSY BIT(0) + +#define MT7621_SPI_TRANS 0x00 +#define SPITRANS_BUSY BIT(16) + +#define MT7621_SPI_OPCODE 0x04 +#define MT7621_SPI_DATA0 0x08 +#define MT7621_SPI_DATA4 0x18 +#define SPI_CTL_TX_RX_CNT_MASK 0xff +#define SPI_CTL_START BIT(8) + +#define MT7621_SPI_POLAR 0x38 +#define MT7621_SPI_MASTER 0x28 +#define MT7621_SPI_MOREBUF 0x2c +#define MT7621_SPI_SPACE 0x3c + +#define MT7621_CPHA BIT(5) +#define MT7621_CPOL BIT(4) +#define MT7621_LSB_FIRST BIT(3) + +#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH) + +struct mt7621_spi; + +struct mt7621_spi { + struct spi_master *master; + void __iomem *base; + unsigned int sys_freq; + unsigned int speed; + struct clk *clk; + spinlock_t lock; + + struct mt7621_spi_ops *ops; +}; + +static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) +{ + return spi_master_get_devdata(spi->master); +} + +static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg) +{ + return ioread32(rs->base + reg); +} + +static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val) +{ + iowrite32(val, rs->base + reg); +} + +static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex) +{ + u32 master = mt7621_spi_read(rs, MT7621_SPI_MASTER); + + master |= 7 << 29; + master |= 1 << 2; + if (duplex) + master |= 1 << 10; + else + master &= ~(1 << 10); + + mt7621_spi_write(rs, MT7621_SPI_MASTER, master); +} + +static void mt7621_spi_set_cs(struct spi_device *spi, int enable) +{ + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + int cs = spi->chip_select; + u32 polar = 0; + + mt7621_spi_reset(rs, cs); + if (enable) + polar = BIT(cs); + mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); +} + +static int mt7621_spi_prepare(struct spi_device *spi, unsigned int speed) +{ + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + u32 rate; + u32 reg; + + dev_dbg(&spi->dev, "speed:%u\n", speed); + + rate = DIV_ROUND_UP(rs->sys_freq, speed); + dev_dbg(&spi->dev, "rate-1:%u\n", rate); + + if (rate > 4097) + return -EINVAL; + + if (rate < 2) + rate = 2; + + reg = mt7621_spi_read(rs, MT7621_SPI_MASTER); + reg &= ~(0xfff << 16); + reg |= (rate - 2) << 16; + rs->speed = speed; + + reg &= ~MT7621_LSB_FIRST; + if (spi->mode & SPI_LSB_FIRST) + reg |= MT7621_LSB_FIRST; + + reg &= ~(MT7621_CPHA | MT7621_CPOL); + switch(spi->mode & (SPI_CPOL | SPI_CPHA)) { + case SPI_MODE_0: + break; + case SPI_MODE_1: + reg |= MT7621_CPHA; + break; + case SPI_MODE_2: + reg |= MT7621_CPOL; + break; + case SPI_MODE_3: + reg |= MT7621_CPOL | MT7621_CPHA; + break; + } + mt7621_spi_write(rs, MT7621_SPI_MASTER, reg); + + return 0; +} + +static inline int mt7621_spi_wait_till_ready(struct spi_device *spi) +{ + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + int i; + + for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) { + u32 status; + + status = mt7621_spi_read(rs, MT7621_SPI_TRANS); + if ((status & SPITRANS_BUSY) == 0) { + return 0; + } + cpu_relax(); + udelay(1); + } + + return -ETIMEDOUT; +} + +static int mt7621_spi_transfer_half_duplex(struct spi_master *master, + struct spi_message *m) +{ + struct mt7621_spi *rs = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + unsigned int speed = spi->max_speed_hz; + struct spi_transfer *t = NULL; + int status = 0; + int i, len = 0; + int rx_len = 0; + u32 data[9] = { 0 }; + u32 val; + + mt7621_spi_wait_till_ready(spi); + + list_for_each_entry(t, &m->transfers, transfer_list) { + const u8 *buf = t->tx_buf; + + if (t->rx_buf) + rx_len += t->len; + + if (!buf) + continue; + + if (t->speed_hz < speed) + speed = t->speed_hz; + + if (WARN_ON(len + t->len > 36)) { + status = -EIO; + goto msg_done; + } + + for (i = 0; i < t->len; i++, len++) + data[len / 4] |= buf[i] << (8 * (len & 3)); + } + + if (WARN_ON(rx_len > 32)) { + status = -EIO; + goto msg_done; + } + + if (mt7621_spi_prepare(spi, speed)) { + status = -EIO; + goto msg_done; + } + data[0] = swab32(data[0]); + if (len < 4) + data[0] >>= (4 - len) * 8; + + for (i = 0; i < len; i += 4) + mt7621_spi_write(rs, MT7621_SPI_OPCODE + i, data[i / 4]); + + val = (min_t(int, len, 4) * 8) << 24; + if (len > 4) + val |= (len - 4) * 8; + val |= (rx_len * 8) << 12; + mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); + + mt7621_spi_set_cs(spi, 1); + + val = mt7621_spi_read(rs, MT7621_SPI_TRANS); + val |= SPI_CTL_START; + mt7621_spi_write(rs, MT7621_SPI_TRANS, val); + + mt7621_spi_wait_till_ready(spi); + + mt7621_spi_set_cs(spi, 0); + + for (i = 0; i < rx_len; i += 4) + data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); + + m->actual_length = len + rx_len; + + len = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { + u8 *buf = t->rx_buf; + + if (!buf) + continue; + + for (i = 0; i < t->len; i++, len++) + buf[i] = data[len / 4] >> (8 * (len & 3)); + } + +msg_done: + m->status = status; + spi_finalize_current_message(master); + + return 0; +} + +static int mt7621_spi_transfer_full_duplex(struct spi_master *master, + struct spi_message *m) +{ + struct mt7621_spi *rs = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + unsigned int speed = spi->max_speed_hz; + struct spi_transfer *t = NULL; + int status = 0; + int i, len = 0; + int rx_len = 0; + u32 data[9] = { 0 }; + u32 val = 0; + + mt7621_spi_wait_till_ready(spi); + + list_for_each_entry(t, &m->transfers, transfer_list) { + const u8 *buf = t->tx_buf; + + if (t->rx_buf) + rx_len += t->len; + + if (!buf) + continue; + + if (WARN_ON(len + t->len > 16)) { + status = -EIO; + goto msg_done; + } + + for (i = 0; i < t->len; i++, len++) + data[len / 4] |= buf[i] << (8 * (len & 3)); + if (speed > t->speed_hz) + speed = t->speed_hz; + } + + if (WARN_ON(rx_len > 16)) { + status = -EIO; + goto msg_done; + } + + if (mt7621_spi_prepare(spi, speed)) { + status = -EIO; + goto msg_done; + } + + for (i = 0; i < len; i += 4) + mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]); + + val |= len * 8; + val |= (rx_len * 8) << 12; + mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); + + mt7621_spi_set_cs(spi, 1); + + val = mt7621_spi_read(rs, MT7621_SPI_TRANS); + val |= SPI_CTL_START; + mt7621_spi_write(rs, MT7621_SPI_TRANS, val); + + mt7621_spi_wait_till_ready(spi); + + mt7621_spi_set_cs(spi, 0); + + for (i = 0; i < rx_len; i += 4) + data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i); + + m->actual_length = rx_len; + + len = 0; + list_for_each_entry(t, &m->transfers, transfer_list) { + u8 *buf = t->rx_buf; + + if (!buf) + continue; + + for (i = 0; i < t->len; i++, len++) + buf[i] = data[len / 4] >> (8 * (len & 3)); + } + +msg_done: + m->status = status; + spi_finalize_current_message(master); + + return 0; +} + +static int mt7621_spi_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct spi_device *spi = m->spi; + int cs = spi->chip_select; + + if (cs) + return mt7621_spi_transfer_full_duplex(master, m); + return mt7621_spi_transfer_half_duplex(master, m); +} + +static int mt7621_spi_setup(struct spi_device *spi) +{ + struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); + + if ((spi->max_speed_hz == 0) || + (spi->max_speed_hz > (rs->sys_freq / 2))) + spi->max_speed_hz = (rs->sys_freq / 2); + + if (spi->max_speed_hz < (rs->sys_freq / 4097)) { + dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n", + spi->max_speed_hz); + return -EINVAL; + } + + return 0; +} + +static const struct of_device_id mt7621_spi_match[] = { + { .compatible = "ralink,mt7621-spi" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt7621_spi_match); + +static size_t max_transfer_size(struct spi_device *spi) +{ + return 32; +} + +static int mt7621_spi_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct spi_master *master; + struct mt7621_spi *rs; + unsigned long flags; + void __iomem *base; + struct resource *r; + int status = 0; + struct clk *clk; + struct mt7621_spi_ops *ops; + + match = of_match_device(mt7621_spi_match, &pdev->dev); + if (!match) + return -EINVAL; + ops = (struct mt7621_spi_ops *)match->data; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n", + status); + return PTR_ERR(clk); + } + + status = clk_prepare_enable(clk); + if (status) + return status; + + master = spi_alloc_master(&pdev->dev, sizeof(*rs)); + if (master == NULL) { + dev_info(&pdev->dev, "master allocation failed\n"); + return -ENOMEM; + } + + master->mode_bits = RT2880_SPI_MODE_BITS; + + master->setup = mt7621_spi_setup; + master->transfer_one_message = mt7621_spi_transfer_one_message; + master->bits_per_word_mask = SPI_BPW_MASK(8); + master->dev.of_node = pdev->dev.of_node; + master->num_chipselect = 2; + master->max_transfer_size = max_transfer_size; + + dev_set_drvdata(&pdev->dev, master); + + rs = spi_master_get_devdata(master); + rs->base = base; + rs->clk = clk; + rs->master = master; + rs->sys_freq = clk_get_rate(rs->clk); + rs->ops = ops; + dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); + spin_lock_irqsave(&rs->lock, flags); + + device_reset(&pdev->dev); + + mt7621_spi_reset(rs, 0); + + return spi_register_master(master); +} + +static int mt7621_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master; + struct mt7621_spi *rs; + + master = dev_get_drvdata(&pdev->dev); + rs = spi_master_get_devdata(master); + + clk_disable(rs->clk); + spi_unregister_master(master); + + return 0; +} + +MODULE_ALIAS("platform:" DRIVER_NAME); + +static struct platform_driver mt7621_spi_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = mt7621_spi_match, + }, + .probe = mt7621_spi_probe, + .remove = mt7621_spi_remove, +}; + +module_platform_driver(mt7621_spi_driver); + +MODULE_DESCRIPTION("MT7621 SPI driver"); +MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index 30532d8c310b..e461168313bf 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -993,8 +993,7 @@ static int xlr_net_probe(struct platform_device *pdev) /* * Allocate our adapter data structure and attach it to the device. */ - adapter = (struct xlr_adapter *) - devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL); + adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL); if (!adapter) return -ENOMEM; diff --git a/drivers/staging/pi433/Documentation/pi433.txt b/drivers/staging/pi433/Documentation/pi433.txt index 7d9dc2244848..d0b7000faafc 100644 --- a/drivers/staging/pi433/Documentation/pi433.txt +++ b/drivers/staging/pi433/Documentation/pi433.txt @@ -92,7 +92,7 @@ rf params: shaping0_3 - gauss filter with BT 0.3 (FSK only) shapingBR - filter cut off at BR (OOK only) shaping2BR - filter cut off at 2*BR (OOK only) - paRamp (FSK only) + pa_ramp (FSK only) ramp3400 - amp ramps up in 3.4ms ramp2000 - amp ramps up in 2.0ms ramp1000 - amp ramps up in 1ms @@ -180,7 +180,7 @@ rf params: threshold value for the signal strength on the receiver input. If this value is exceeded, a reception cycle starts Allowed values: 0...255 - thresholdDecrement + threshold_decrement in order to adapt to different levels of singnal strength, over time the receiver gets more and more sensitive. This value determs, how fast the sensitivity increases. @@ -192,11 +192,11 @@ rf params: step_4_0db - increase in 4 db steps step_5_0db - increase in 5 db steps step_6_0db - increase in 6 db steps - antennaImpedance + antenna_impedance sets the electrical adoption of the antenna - fiftyOhm - for antennas with an impedance of 50Ohm - twohundretOhm - for antennas with an impedance of 200Ohm - lnaGain + fifty_ohm - for antennas with an impedance of 50Ohm + two_hundred_ohm - for antennas with an impedance of 200Ohm + lna_gain sets the gain of the low noise amp automatic - lna gain is determined by an agc max - lna gain is set to maximum @@ -215,9 +215,9 @@ rf params: Allowd values: 0...7 dagc; operation mode of the digital automatic gain control - normalMode + normal_mode improve - improve4LowModulationIndex + improve_for_low_modulation_index packet format: enable_sync @@ -232,12 +232,12 @@ rf params: amount of bytes that were requested by the read request. Attention: should be used in combination with sync, only enable_address_filtering; - filteringOff - no address filtering will take place - nodeAddress - all telegrams, not matching the node - address will be internally discarded - nodeOrBroadcastAddress - all telegrams, neither matching the - node, nor the broadcast address will - be internally discarded + filtering_off - no address filtering will take place + node_address - all telegrams, not matching the node + address will be internally discarded + node_or_broadcast_address - all telegrams, neither matching the + node, nor the broadcast address will + be internally discarded Attention: Sync option must be enabled in order to use this feature enable_crc optionOn - a crc will be calculated over the payload of diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index edcd7e798f99..d1e0ddbc79ce 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -187,10 +187,12 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) ret = rf69_set_ook_threshold_dec(dev->spi, rx_cfg->threshold_decrement); if (ret < 0) return ret; - ret = rf69_set_bandwidth(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent); + ret = rf69_set_bandwidth(dev->spi, rx_cfg->bw_mantisse, + rx_cfg->bw_exponent); if (ret < 0) return ret; - ret = rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, rx_cfg->bw_exponent); + ret = rf69_set_bandwidth_during_afc(dev->spi, rx_cfg->bw_mantisse, + rx_cfg->bw_exponent); if (ret < 0) return ret; ret = rf69_set_dagc(dev->spi, rx_cfg->dagc); @@ -206,7 +208,8 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) if (ret < 0) return ret; - ret = rf69_set_fifo_fill_condition(dev->spi, afterSyncInterrupt); + ret = rf69_set_fifo_fill_condition(dev->spi, + after_sync_interrupt); if (ret < 0) return ret; } else { @@ -219,15 +222,16 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) return ret; } if (rx_cfg->enable_length_byte == OPTION_ON) { - ret = rf69_set_packet_format(dev->spi, packetLengthVar); + ret = rf69_set_packet_format(dev->spi, packet_length_var); if (ret < 0) return ret; } else { - ret = rf69_set_packet_format(dev->spi, packetLengthFix); + ret = rf69_set_packet_format(dev->spi, packet_length_fix); if (ret < 0) return ret; } - ret = rf69_set_adressFiltering(dev->spi, rx_cfg->enable_address_filtering); + ret = rf69_set_address_filtering(dev->spi, + rx_cfg->enable_address_filtering); if (ret < 0) return ret; @@ -253,7 +257,7 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) payload_length = rx_cfg->fixed_message_length; if (rx_cfg->enable_length_byte == OPTION_ON) payload_length++; - if (rx_cfg->enable_address_filtering != filteringOff) + if (rx_cfg->enable_address_filtering != filtering_off) payload_length++; ret = rf69_set_payload_length(dev->spi, payload_length); if (ret < 0) @@ -270,11 +274,12 @@ rf69_set_rx_cfg(struct pi433_device *dev, struct pi433_rx_cfg *rx_cfg) if (ret < 0) return ret; } - if (rx_cfg->enable_address_filtering != filteringOff) { + if (rx_cfg->enable_address_filtering != filtering_off) { ret = rf69_set_node_address(dev->spi, rx_cfg->node_address); if (ret < 0) return ret; - ret = rf69_set_broadcast_address(dev->spi, rx_cfg->broadcast_address); + ret = rf69_set_broadcast_address(dev->spi, + rx_cfg->broadcast_address); if (ret < 0) return ret; } @@ -311,7 +316,8 @@ rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg) /* packet format enable */ if (tx_cfg->enable_preamble == OPTION_ON) { - ret = rf69_set_preamble_length(dev->spi, tx_cfg->preamble_length); + ret = rf69_set_preamble_length(dev->spi, + tx_cfg->preamble_length); if (ret < 0) return ret; } else { @@ -331,11 +337,11 @@ rf69_set_tx_cfg(struct pi433_device *dev, struct pi433_tx_cfg *tx_cfg) } if (tx_cfg->enable_length_byte == OPTION_ON) { - ret = rf69_set_packet_format(dev->spi, packetLengthVar); + ret = rf69_set_packet_format(dev->spi, packet_length_var); if (ret < 0) return ret; } else { - ret = rf69_set_packet_format(dev->spi, packetLengthFix); + ret = rf69_set_packet_format(dev->spi, packet_length_fix); if (ret < 0) return ret; } @@ -437,7 +443,7 @@ pi433_receive(void *data) return retval; /* now check RSSI, if low wait for getting high (RSSI interrupt) */ - while (!rf69_get_flag(dev->spi, rssiExceededThreshold)) { + while (!rf69_get_flag(dev->spi, rssi_exceeded_threshold)) { /* allow tx to interrupt us while waiting for high RSSI */ dev->interrupt_rx_allowed = true; wake_up_interruptible(&dev->tx_wait_queue); @@ -446,7 +452,7 @@ pi433_receive(void *data) dev_dbg(dev->dev, "rx: going to wait for high RSSI level"); retval = wait_event_interruptible(dev->rx_wait_queue, rf69_get_flag(dev->spi, - rssiExceededThreshold)); + rssi_exceeded_threshold)); if (retval) /* wait was interrupted */ goto abort; dev->interrupt_rx_allowed = false; @@ -470,10 +476,12 @@ pi433_receive(void *data) goto abort; } bytes_total = dev->rx_cfg.fixed_message_length; - dev_dbg(dev->dev, "rx: msg len set to %d by fixed length", bytes_total); + dev_dbg(dev->dev, "rx: msg len set to %d by fixed length", + bytes_total); } else { bytes_total = dev->rx_buffer_size; - dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", bytes_total); + dev_dbg(dev->dev, "rx: msg len set to %d as requested by read", + bytes_total); } /* length byte enabled? */ @@ -489,11 +497,12 @@ pi433_receive(void *data) goto abort; } dev->free_in_fifo++; - dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", bytes_total); + dev_dbg(dev->dev, "rx: msg len reset to %d due to length byte", + bytes_total); } /* address byte enabled? */ - if (dev->rx_cfg.enable_address_filtering != filteringOff) { + if (dev->rx_cfg.enable_address_filtering != filtering_off) { u8 dummy; bytes_total--; @@ -519,7 +528,8 @@ pi433_receive(void *data) /* need to drop bytes or acquire? */ if (dev->rx_bytes_to_drop > dev->rx_bytes_dropped) - bytes_to_read = dev->rx_bytes_to_drop - dev->rx_bytes_dropped; + bytes_to_read = dev->rx_bytes_to_drop - + dev->rx_bytes_dropped; else bytes_to_read = bytes_total - dev->rx_position; @@ -620,8 +630,10 @@ pi433_tx_thread(void *data) device->buffer[position++] = tx_cfg.address_byte; /* finally get message data from fifo */ - retval = kfifo_out(&device->tx_fifo, &device->buffer[position], sizeof(device->buffer) - position); - dev_dbg(device->dev, "read %d message byte(s) from fifo queue.", retval); + retval = kfifo_out(&device->tx_fifo, &device->buffer[position], + sizeof(device->buffer) - position); + dev_dbg(device->dev, + "read %d message byte(s) from fifo queue.", retval); mutex_unlock(&device->tx_fifo_lock); /* if rx is active, we need to interrupt the waiting for @@ -699,12 +711,13 @@ pi433_tx_thread(void *data) while ((repetitions > 0) && (size > position)) { if ((size - position) > device->free_in_fifo) { /* msg to big for fifo - take a part */ - int temp = device->free_in_fifo; + int write_size = device->free_in_fifo; + device->free_in_fifo = 0; rf69_write_fifo(spi, &device->buffer[position], - temp); - position += temp; + write_size); + position += write_size; } else { /* msg fits into fifo - take all */ device->free_in_fifo -= size; @@ -724,7 +737,8 @@ pi433_tx_thread(void *data) } /* we are done. Wait for packet to get sent */ - dev_dbg(device->dev, "thread: wait for packet to get sent/fifo to be empty"); + dev_dbg(device->dev, + "thread: wait for packet to get sent/fifo to be empty"); wait_event_interruptible(device->fifo_wait_queue, device->free_in_fifo == FIFO_SIZE || kthread_should_stop()); @@ -819,7 +833,8 @@ pi433_write(struct file *filp, const char __user *buf, * - message */ mutex_lock(&device->tx_fifo_lock); - retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, sizeof(instance->tx_cfg)); + retval = kfifo_in(&device->tx_fifo, &instance->tx_cfg, + sizeof(instance->tx_cfg)); if (retval != sizeof(instance->tx_cfg)) goto abort; @@ -983,7 +998,7 @@ static int pi433_release(struct inode *inode, struct file *filp) /*-------------------------------------------------------------------------*/ -static int setup_GPIOs(struct pi433_device *device) +static int setup_gpio(struct pi433_device *device) { char name[5]; int retval; @@ -996,10 +1011,12 @@ static int setup_GPIOs(struct pi433_device *device) for (i = 0; i < NUM_DIO; i++) { /* "construct" name and get the gpio descriptor */ snprintf(name, sizeof(name), "DIO%d", i); - device->gpiod[i] = gpiod_get(&device->spi->dev, name, 0 /*GPIOD_IN*/); + device->gpiod[i] = gpiod_get(&device->spi->dev, name, + 0 /*GPIOD_IN*/); if (device->gpiod[i] == ERR_PTR(-ENOENT)) { - dev_dbg(&device->spi->dev, "Could not find entry for %s. Ignoring.", name); + dev_dbg(&device->spi->dev, + "Could not find entry for %s. Ignoring.", name); continue; } @@ -1043,7 +1060,7 @@ static int setup_GPIOs(struct pi433_device *device) return 0; } -static void free_GPIOs(struct pi433_device *device) +static void free_gpio(struct pi433_device *device) { int i; @@ -1158,7 +1175,7 @@ static int pi433_probe(struct spi_device *spi) mutex_init(&device->rx_lock); /* setup GPIO (including irq_handler) for the different DIOs */ - retval = setup_GPIOs(device); + retval = setup_gpio(device); if (retval) { dev_dbg(&spi->dev, "setup of GPIOs failed"); goto GPIO_failed; @@ -1183,7 +1200,7 @@ static int pi433_probe(struct spi_device *spi) retval = rf69_set_output_power_level(spi, 13); if (retval < 0) goto minor_failed; - retval = rf69_set_antenna_impedance(spi, fiftyOhm); + retval = rf69_set_antenna_impedance(spi, fifty_ohm); if (retval < 0) goto minor_failed; @@ -1245,7 +1262,7 @@ send_thread_failed: device_create_failed: pi433_free_minor(device); minor_failed: - free_GPIOs(device); + free_gpio(device); GPIO_failed: kfree(device); @@ -1257,7 +1274,7 @@ static int pi433_remove(struct spi_device *spi) struct pi433_device *device = spi_get_drvdata(spi); /* free GPIOs */ - free_GPIOs(device); + free_gpio(device); /* make sure ops on existing fds can abort cleanly */ device->spi = NULL; @@ -1315,7 +1332,7 @@ static int __init pi433_init(void) * that will key udev/mdev to add/remove /dev nodes. Last, register * Last, register the driver which manages those device numbers. */ - status = alloc_chrdev_region(&pi433_dev, 0 /*firstminor*/, N_PI433_MINORS /*count*/, "pi433" /*name*/); + status = alloc_chrdev_region(&pi433_dev, 0, N_PI433_MINORS, "pi433"); if (status < 0) return status; diff --git a/drivers/staging/pi433/pi433_if.h b/drivers/staging/pi433/pi433_if.h index 7314f69af198..b6e214c29ddf 100644 --- a/drivers/staging/pi433/pi433_if.h +++ b/drivers/staging/pi433/pi433_if.h @@ -67,9 +67,9 @@ struct pi433_tx_cfg { enum modulation modulation; enum mod_shaping mod_shaping; - enum paRamp pa_ramp; + enum pa_ramp pa_ramp; - enum txStartCondition tx_start_condition; + enum tx_start_condition tx_start_condition; __u16 repetitions; @@ -115,9 +115,9 @@ struct pi433_rx_cfg { enum modulation modulation; __u8 rssi_threshold; - enum thresholdDecrement threshold_decrement; - enum antennaImpedance antenna_impedance; - enum lnaGain lna_gain; + enum threshold_decrement threshold_decrement; + enum antenna_impedance antenna_impedance; + enum lna_gain lna_gain; enum mantisse bw_mantisse; /* normal: 0x50 */ __u8 bw_exponent; /* during AFC: 0x8b */ enum dagc dagc; @@ -125,7 +125,7 @@ struct pi433_rx_cfg { /* packet format */ enum option_on_off enable_sync; enum option_on_off enable_length_byte; /* should be used in combination with sync, only */ - enum addressFiltering enable_address_filtering; /* operational with sync, only */ + enum address_filtering enable_address_filtering; /* operational with sync, only */ enum option_on_off enable_crc; /* only operational, if sync on and fixed length or length byte is used */ __u8 sync_length; diff --git a/drivers/staging/pi433/rf69.c b/drivers/staging/pi433/rf69.c index 7ccdff6ae213..5b0554823263 100644 --- a/drivers/staging/pi433/rf69.c +++ b/drivers/staging/pi433/rf69.c @@ -151,11 +151,11 @@ int rf69_set_modulation(struct spi_device *spi, enum modulation modulation) static enum modulation rf69_get_modulation(struct spi_device *spi) { - u8 currentValue; + u8 modulation_reg; - currentValue = rf69_read_reg(spi, REG_DATAMODUL); + modulation_reg = rf69_read_reg(spi, REG_DATAMODUL); - switch (currentValue & MASK_DATAMODUL_MODULATION_TYPE) { + switch (modulation_reg & MASK_DATAMODUL_MODULATION_TYPE) { case DATAMODUL_MODULATION_TYPE_OOK: return OOK; case DATAMODUL_MODULATION_TYPE_FSK: @@ -201,26 +201,26 @@ int rf69_set_modulation_shaping(struct spi_device *spi, } } -int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate) +int rf69_set_bit_rate(struct spi_device *spi, u16 bit_rate) { int retval; - u32 bitRate_min; - u32 bitRate_reg; + u32 bit_rate_min; + u32 bit_rate_reg; u8 msb; u8 lsb; // check input value - bitRate_min = F_OSC / 8388608; // 8388608 = 2^23; - if (bitRate < bitRate_min) { + bit_rate_min = F_OSC / 8388608; // 8388608 = 2^23; + if (bit_rate < bit_rate_min) { dev_dbg(&spi->dev, "setBitRate: illegal input param"); return -EINVAL; } // calculate reg settings - bitRate_reg = (F_OSC / bitRate); + bit_rate_reg = (F_OSC / bit_rate); - msb = (bitRate_reg & 0xff00) >> 8; - lsb = (bitRate_reg & 0xff); + msb = (bit_rate_reg & 0xff00) >> 8; + lsb = (bit_rate_reg & 0xff); // transmit to RF 69 retval = rf69_write_reg(spi, REG_BITRATE_MSB, msb); @@ -330,24 +330,24 @@ int rf69_disable_amplifier(struct spi_device *spi, u8 amplifier_mask) return rf69_clear_bit(spi, REG_PALEVEL, amplifier_mask); } -int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel) +int rf69_set_output_power_level(struct spi_device *spi, u8 power_level) { // TODO: Dependency to PA0,1,2 setting - powerLevel += 18; + power_level += 18; // check input value - if (powerLevel > 0x1f) { + if (power_level > 0x1f) { dev_dbg(&spi->dev, "set: illegal input param"); return -EINVAL; } // write value - return rf69_read_mod_write(spi, REG_PALEVEL, MASK_PALEVEL_OUTPUT_POWER, powerLevel); + return rf69_read_mod_write(spi, REG_PALEVEL, MASK_PALEVEL_OUTPUT_POWER, power_level); } -int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp) +int rf69_set_pa_ramp(struct spi_device *spi, enum pa_ramp pa_ramp) { - switch (paRamp) { + switch (pa_ramp) { case ramp3400: return rf69_write_reg(spi, REG_PARAMP, PARAMP_3400); case ramp2000: @@ -386,12 +386,12 @@ int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp) } } -int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance) +int rf69_set_antenna_impedance(struct spi_device *spi, enum antenna_impedance antenna_impedance) { - switch (antennaImpedance) { - case fiftyOhm: + switch (antenna_impedance) { + case fifty_ohm: return rf69_clear_bit(spi, REG_LNA, MASK_LNA_ZIN); - case twohundretOhm: + case two_hundred_ohm: return rf69_set_bit(spi, REG_LNA, MASK_LNA_ZIN); default: dev_dbg(&spi->dev, "set: illegal input param"); @@ -399,9 +399,9 @@ int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance ant } } -int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain) +int rf69_set_lna_gain(struct spi_device *spi, enum lna_gain lna_gain) { - switch (lnaGain) { + switch (lna_gain) { case automatic: return rf69_read_mod_write(spi, REG_LNA, MASK_LNA_GAIN, LNA_GAIN_AUTO); case max: @@ -425,7 +425,7 @@ int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain) static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, enum mantisse mantisse, u8 exponent) { - u8 newValue; + u8 bandwidth; // check value for mantisse and exponent if (exponent > 7) { @@ -441,29 +441,29 @@ static int rf69_set_bandwidth_intern(struct spi_device *spi, u8 reg, } // read old value - newValue = rf69_read_reg(spi, reg); + bandwidth = rf69_read_reg(spi, reg); // "delete" mantisse and exponent = just keep the DCC setting - newValue = newValue & MASK_BW_DCC_FREQ; + bandwidth = bandwidth & MASK_BW_DCC_FREQ; // add new mantisse switch (mantisse) { case mantisse16: - newValue = newValue | BW_MANT_16; + bandwidth = bandwidth | BW_MANT_16; break; case mantisse20: - newValue = newValue | BW_MANT_20; + bandwidth = bandwidth | BW_MANT_20; break; case mantisse24: - newValue = newValue | BW_MANT_24; + bandwidth = bandwidth | BW_MANT_24; break; } // add new exponent - newValue = newValue | exponent; + bandwidth = bandwidth | exponent; // write back - return rf69_write_reg(spi, reg, newValue); + return rf69_write_reg(spi, reg, bandwidth); } int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent) @@ -476,9 +476,9 @@ int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse return rf69_set_bandwidth_intern(spi, REG_AFCBW, mantisse, exponent); } -int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement) +int rf69_set_ook_threshold_dec(struct spi_device *spi, enum threshold_decrement threshold_decrement) { - switch (thresholdDecrement) { + switch (threshold_decrement) { case dec_every8th: return rf69_read_mod_write(spi, REG_OOKPEAK, MASK_OOKPEAK_THRESDEC, OOKPEAK_THRESHDEC_EVERY_8TH); case dec_every4th: @@ -501,31 +501,31 @@ int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement t } } -int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value) +int rf69_set_dio_mapping(struct spi_device *spi, u8 dio_number, u8 value) { u8 mask; u8 shift; - u8 regaddr; - u8 regValue; + u8 dio_addr; + u8 dio_value; - switch (DIONumber) { + switch (dio_number) { case 0: - mask = MASK_DIO0; shift = SHIFT_DIO0; regaddr = REG_DIOMAPPING1; + mask = MASK_DIO0; shift = SHIFT_DIO0; dio_addr = REG_DIOMAPPING1; break; case 1: - mask = MASK_DIO1; shift = SHIFT_DIO1; regaddr = REG_DIOMAPPING1; + mask = MASK_DIO1; shift = SHIFT_DIO1; dio_addr = REG_DIOMAPPING1; break; case 2: - mask = MASK_DIO2; shift = SHIFT_DIO2; regaddr = REG_DIOMAPPING1; + mask = MASK_DIO2; shift = SHIFT_DIO2; dio_addr = REG_DIOMAPPING1; break; case 3: - mask = MASK_DIO3; shift = SHIFT_DIO3; regaddr = REG_DIOMAPPING1; + mask = MASK_DIO3; shift = SHIFT_DIO3; dio_addr = REG_DIOMAPPING1; break; case 4: - mask = MASK_DIO4; shift = SHIFT_DIO4; regaddr = REG_DIOMAPPING2; + mask = MASK_DIO4; shift = SHIFT_DIO4; dio_addr = REG_DIOMAPPING2; break; case 5: - mask = MASK_DIO5; shift = SHIFT_DIO5; regaddr = REG_DIOMAPPING2; + mask = MASK_DIO5; shift = SHIFT_DIO5; dio_addr = REG_DIOMAPPING2; break; default: dev_dbg(&spi->dev, "set: illegal input param"); @@ -533,33 +533,33 @@ int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value) } // read reg - regValue = rf69_read_reg(spi, regaddr); + dio_value = rf69_read_reg(spi, dio_addr); // delete old value - regValue = regValue & ~mask; + dio_value = dio_value & ~mask; // add new value - regValue = regValue | value << shift; + dio_value = dio_value | value << shift; // write back - return rf69_write_reg(spi, regaddr, regValue); + return rf69_write_reg(spi, dio_addr, dio_value); } bool rf69_get_flag(struct spi_device *spi, enum flag flag) { switch (flag) { - case modeSwitchCompleted: + case mode_switch_completed: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_MODE_READY); - case readyToReceive: + case ready_to_receive: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_RX_READY); - case readyToSend: + case ready_to_send: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_TX_READY); - case pllLocked: + case pll_locked: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_PLL_LOCK); - case rssiExceededThreshold: + case rssi_exceeded_threshold: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_RSSI); case timeout: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_TIMEOUT); case automode: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_AUTOMODE); - case syncAddressMatch: + case sync_address_match: return (rf69_read_reg(spi, REG_IRQFLAGS1) & MASK_IRQFLAGS1_SYNC_ADDRESS_MATCH); case fifo_full: return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_FULL); @@ -571,13 +571,13 @@ bool rf69_get_flag(struct spi_device *spi, enum flag flag) return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_LEVEL); case fifo_overrun: return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_FIFO_OVERRUN); - case packetSent: + case packet_sent: return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_PACKET_SENT); case payload_ready: return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_PAYLOAD_READY); - case crcOk: + case crc_ok: return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_CRC_OK); - case batteryLow: + case battery_low: return (rf69_read_reg(spi, REG_IRQFLAGS2) & MASK_IRQFLAGS2_LOW_BAT); default: return false; } @@ -590,7 +590,7 @@ int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold) return rf69_write_reg(spi, REG_RSSITHRESH, threshold); } -int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength) +int rf69_set_preamble_length(struct spi_device *spi, u16 preamble_length) { int retval; u8 msb, lsb; @@ -598,8 +598,8 @@ int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength) /* no value check needed - u16 exactly matches register size */ /* calculate reg settings */ - msb = (preambleLength & 0xff00) >> 8; - lsb = (preambleLength & 0xff); + msb = (preamble_length & 0xff00) >> 8; + lsb = (preamble_length & 0xff); /* transmit to chip */ retval = rf69_write_reg(spi, REG_PREAMBLE_MSB, msb); @@ -625,7 +625,7 @@ int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifo_fill_conditio switch (fifo_fill_condition) { case always: return rf69_set_bit(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_FIFO_FILL_CONDITION); - case afterSyncInterrupt: + case after_sync_interrupt: return rf69_clear_bit(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_FIFO_FILL_CONDITION); default: dev_dbg(&spi->dev, "set: illegal input param"); @@ -633,40 +633,40 @@ int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifo_fill_conditio } } -int rf69_set_sync_size(struct spi_device *spi, u8 syncSize) +int rf69_set_sync_size(struct spi_device *spi, u8 sync_size) { // check input value - if (syncSize > 0x07) { + if (sync_size > 0x07) { dev_dbg(&spi->dev, "set: illegal input param"); return -EINVAL; } // write value - return rf69_read_mod_write(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_SYNC_SIZE, (syncSize << 3)); + return rf69_read_mod_write(spi, REG_SYNC_CONFIG, MASK_SYNC_CONFIG_SYNC_SIZE, (sync_size << 3)); } -int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]) +int rf69_set_sync_values(struct spi_device *spi, u8 sync_values[8]) { int retval = 0; - retval += rf69_write_reg(spi, REG_SYNCVALUE1, syncValues[0]); - retval += rf69_write_reg(spi, REG_SYNCVALUE2, syncValues[1]); - retval += rf69_write_reg(spi, REG_SYNCVALUE3, syncValues[2]); - retval += rf69_write_reg(spi, REG_SYNCVALUE4, syncValues[3]); - retval += rf69_write_reg(spi, REG_SYNCVALUE5, syncValues[4]); - retval += rf69_write_reg(spi, REG_SYNCVALUE6, syncValues[5]); - retval += rf69_write_reg(spi, REG_SYNCVALUE7, syncValues[6]); - retval += rf69_write_reg(spi, REG_SYNCVALUE8, syncValues[7]); + retval += rf69_write_reg(spi, REG_SYNCVALUE1, sync_values[0]); + retval += rf69_write_reg(spi, REG_SYNCVALUE2, sync_values[1]); + retval += rf69_write_reg(spi, REG_SYNCVALUE3, sync_values[2]); + retval += rf69_write_reg(spi, REG_SYNCVALUE4, sync_values[3]); + retval += rf69_write_reg(spi, REG_SYNCVALUE5, sync_values[4]); + retval += rf69_write_reg(spi, REG_SYNCVALUE6, sync_values[5]); + retval += rf69_write_reg(spi, REG_SYNCVALUE7, sync_values[6]); + retval += rf69_write_reg(spi, REG_SYNCVALUE8, sync_values[7]); return retval; } -int rf69_set_packet_format(struct spi_device *spi, enum packetFormat packetFormat) +int rf69_set_packet_format(struct spi_device *spi, enum packet_format packet_format) { - switch (packetFormat) { - case packetLengthVar: + switch (packet_format) { + case packet_length_var: return rf69_set_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE); - case packetLengthFix: + case packet_length_fix: return rf69_clear_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_PAKET_FORMAT_VARIABLE); default: dev_dbg(&spi->dev, "set: illegal input param"); @@ -684,14 +684,14 @@ int rf69_disable_crc(struct spi_device *spi) return rf69_clear_bit(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_CRC_ON); } -int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering) +int rf69_set_address_filtering(struct spi_device *spi, enum address_filtering address_filtering) { - switch (addressFiltering) { - case filteringOff: + switch (address_filtering) { + case filtering_off: return rf69_read_mod_write(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_ADDRESSFILTERING, PACKETCONFIG1_ADDRESSFILTERING_OFF); - case nodeAddress: + case node_address: return rf69_read_mod_write(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_ADDRESSFILTERING, PACKETCONFIG1_ADDRESSFILTERING_NODE); - case nodeOrBroadcastAddress: + case node_or_broadcast_address: return rf69_read_mod_write(spi, REG_PACKETCONFIG1, MASK_PACKETCONFIG1_ADDRESSFILTERING, PACKETCONFIG1_ADDRESSFILTERING_NODEBROADCAST); default: dev_dbg(&spi->dev, "set: illegal input param"); @@ -704,19 +704,19 @@ int rf69_set_payload_length(struct spi_device *spi, u8 payload_length) return rf69_write_reg(spi, REG_PAYLOAD_LENGTH, payload_length); } -int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress) +int rf69_set_node_address(struct spi_device *spi, u8 node_address) { - return rf69_write_reg(spi, REG_NODEADRS, nodeAddress); + return rf69_write_reg(spi, REG_NODEADRS, node_address); } -int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress) +int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcast_address) { - return rf69_write_reg(spi, REG_BROADCASTADRS, broadcastAddress); + return rf69_write_reg(spi, REG_BROADCASTADRS, broadcast_address); } -int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition) +int rf69_set_tx_start_condition(struct spi_device *spi, enum tx_start_condition tx_start_condition) { - switch (txStartCondition) { + switch (tx_start_condition) { case fifo_level: return rf69_clear_bit(spi, REG_FIFO_THRESH, MASK_FIFO_THRESH_TXSTART); case fifo_not_empty: @@ -751,11 +751,11 @@ int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold) int rf69_set_dagc(struct spi_device *spi, enum dagc dagc) { switch (dagc) { - case normalMode: + case normal_mode: return rf69_write_reg(spi, REG_TESTDAGC, DAGC_NORMAL); case improve: return rf69_write_reg(spi, REG_TESTDAGC, DAGC_IMPROVED_LOWBETA0); - case improve4LowModulationIndex: + case improve_for_low_modulation_index: return rf69_write_reg(spi, REG_TESTDAGC, DAGC_IMPROVED_LOWBETA1); default: dev_dbg(&spi->dev, "set: illegal input param"); diff --git a/drivers/staging/pi433/rf69.h b/drivers/staging/pi433/rf69.h index 09d221b8b6df..b9f6850e3316 100644 --- a/drivers/staging/pi433/rf69.h +++ b/drivers/staging/pi433/rf69.h @@ -29,35 +29,35 @@ int rf69_set_mode(struct spi_device *spi, enum mode mode); int rf69_set_data_mode(struct spi_device *spi, u8 data_mode); int rf69_set_modulation(struct spi_device *spi, enum modulation modulation); int rf69_set_modulation_shaping(struct spi_device *spi, enum mod_shaping mod_shaping); -int rf69_set_bit_rate(struct spi_device *spi, u16 bitRate); +int rf69_set_bit_rate(struct spi_device *spi, u16 bit_rate); int rf69_set_deviation(struct spi_device *spi, u32 deviation); int rf69_set_frequency(struct spi_device *spi, u32 frequency); int rf69_enable_amplifier(struct spi_device *spi, u8 amplifier_mask); int rf69_disable_amplifier(struct spi_device *spi, u8 amplifier_mask); -int rf69_set_output_power_level(struct spi_device *spi, u8 powerLevel); -int rf69_set_pa_ramp(struct spi_device *spi, enum paRamp paRamp); -int rf69_set_antenna_impedance(struct spi_device *spi, enum antennaImpedance antennaImpedance); -int rf69_set_lna_gain(struct spi_device *spi, enum lnaGain lnaGain); +int rf69_set_output_power_level(struct spi_device *spi, u8 power_level); +int rf69_set_pa_ramp(struct spi_device *spi, enum pa_ramp pa_ramp); +int rf69_set_antenna_impedance(struct spi_device *spi, enum antenna_impedance antenna_impedance); +int rf69_set_lna_gain(struct spi_device *spi, enum lna_gain lna_gain); int rf69_set_bandwidth(struct spi_device *spi, enum mantisse mantisse, u8 exponent); int rf69_set_bandwidth_during_afc(struct spi_device *spi, enum mantisse mantisse, u8 exponent); -int rf69_set_ook_threshold_dec(struct spi_device *spi, enum thresholdDecrement thresholdDecrement); -int rf69_set_dio_mapping(struct spi_device *spi, u8 DIONumber, u8 value); +int rf69_set_ook_threshold_dec(struct spi_device *spi, enum threshold_decrement threshold_decrement); +int rf69_set_dio_mapping(struct spi_device *spi, u8 dio_number, u8 value); bool rf69_get_flag(struct spi_device *spi, enum flag flag); int rf69_set_rssi_threshold(struct spi_device *spi, u8 threshold); -int rf69_set_preamble_length(struct spi_device *spi, u16 preambleLength); +int rf69_set_preamble_length(struct spi_device *spi, u16 preamble_length); int rf69_enable_sync(struct spi_device *spi); int rf69_disable_sync(struct spi_device *spi); int rf69_set_fifo_fill_condition(struct spi_device *spi, enum fifo_fill_condition fifo_fill_condition); int rf69_set_sync_size(struct spi_device *spi, u8 sync_size); -int rf69_set_sync_values(struct spi_device *spi, u8 syncValues[8]); -int rf69_set_packet_format(struct spi_device *spi, enum packetFormat packetFormat); +int rf69_set_sync_values(struct spi_device *spi, u8 sync_values[8]); +int rf69_set_packet_format(struct spi_device *spi, enum packet_format packet_format); int rf69_enable_crc(struct spi_device *spi); int rf69_disable_crc(struct spi_device *spi); -int rf69_set_adressFiltering(struct spi_device *spi, enum addressFiltering addressFiltering); +int rf69_set_address_filtering(struct spi_device *spi, enum address_filtering address_filtering); int rf69_set_payload_length(struct spi_device *spi, u8 payload_length); -int rf69_set_node_address(struct spi_device *spi, u8 nodeAddress); -int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcastAddress); -int rf69_set_tx_start_condition(struct spi_device *spi, enum txStartCondition txStartCondition); +int rf69_set_node_address(struct spi_device *spi, u8 node_address); +int rf69_set_broadcast_address(struct spi_device *spi, u8 broadcast_address); +int rf69_set_tx_start_condition(struct spi_device *spi, enum tx_start_condition tx_start_condition); int rf69_set_fifo_threshold(struct spi_device *spi, u8 threshold); int rf69_set_dagc(struct spi_device *spi, enum dagc dagc); diff --git a/drivers/staging/pi433/rf69_enum.h b/drivers/staging/pi433/rf69_enum.h index 03440cfa957c..493bd0025453 100644 --- a/drivers/staging/pi433/rf69_enum.h +++ b/drivers/staging/pi433/rf69_enum.h @@ -41,7 +41,7 @@ enum mod_shaping { SHAPING_2BR }; -enum paRamp { +enum pa_ramp { ramp3400, ramp2000, ramp1000, @@ -60,12 +60,12 @@ enum paRamp { ramp10 }; -enum antennaImpedance { - fiftyOhm, - twohundretOhm +enum antenna_impedance { + fifty_ohm, + two_hundred_ohm }; -enum lnaGain { +enum lna_gain { automatic, max, max_minus_6, @@ -82,7 +82,7 @@ enum mantisse { mantisse24 }; -enum thresholdDecrement { +enum threshold_decrement { dec_every8th, dec_every4th, dec_every2nd, @@ -94,50 +94,50 @@ enum thresholdDecrement { }; enum flag { - modeSwitchCompleted, - readyToReceive, - readyToSend, - pllLocked, - rssiExceededThreshold, + mode_switch_completed, + ready_to_receive, + ready_to_send, + pll_locked, + rssi_exceeded_threshold, timeout, automode, - syncAddressMatch, + sync_address_match, fifo_full, // fifo_not_empty, collision with next enum; replaced by following enum... fifo_empty, fifo_level_below_threshold, fifo_overrun, - packetSent, + packet_sent, payload_ready, - crcOk, - batteryLow + crc_ok, + battery_low }; enum fifo_fill_condition { - afterSyncInterrupt, + after_sync_interrupt, always }; -enum packetFormat { - packetLengthFix, - packetLengthVar +enum packet_format { + packet_length_fix, + packet_length_var }; -enum txStartCondition { +enum tx_start_condition { fifo_level, fifo_not_empty }; -enum addressFiltering { - filteringOff, - nodeAddress, - nodeOrBroadcastAddress +enum address_filtering { + filtering_off, + node_address, + node_or_broadcast_address }; enum dagc { - normalMode, + normal_mode, improve, - improve4LowModulationIndex + improve_for_low_modulation_index }; #endif diff --git a/drivers/staging/rtl8188eu/Kconfig b/drivers/staging/rtl8188eu/Kconfig index cb836c59d564..673fdce25530 100644 --- a/drivers/staging/rtl8188eu/Kconfig +++ b/drivers/staging/rtl8188eu/Kconfig @@ -4,6 +4,10 @@ config R8188EU depends on m select WIRELESS_EXT select WEXT_PRIV + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_CCMP + select LIB80211_CRYPT_TKIP ---help--- This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N. If built as a module, it will be called r8188eu. diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c index bb867a987c2b..0b0fdccc7278 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c @@ -577,7 +577,7 @@ u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen) u8 match = false; u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; - if (ie_ptr == NULL) + if (!ie_ptr) return match; eid = ie_ptr[0]; @@ -926,7 +926,7 @@ void rtw_macaddr_cfg(u8 *mac_addr) { u8 mac[ETH_ALEN]; - if (mac_addr == NULL) + if (!mac_addr) return; if (rtw_initmac && mac_pton(rtw_initmac, mac)) { @@ -952,7 +952,7 @@ void rtw_macaddr_cfg(u8 *mac_addr) DBG_88E("MAC Address from efuse error, assign default one !!!\n"); } - DBG_88E("rtw_macaddr_cfg MAC Address = %pM\n", (mac_addr)); + DBG_88E("%s MAC Address = %pM\n", __func__, (mac_addr)); } static int rtw_get_cipher_info(struct wlan_network *pnetwork) @@ -965,7 +965,7 @@ static int rtw_get_cipher_info(struct wlan_network *pnetwork) pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); if (pbuf && (wpa_ielen > 0)) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_ielen: %d", __func__, wpa_ielen)); if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) { pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; pnetwork->BcnInfo.group_cipher = group_cipher; @@ -1014,10 +1014,10 @@ void rtw_get_bcn_info(struct wlan_network *pnetwork) pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; } rtw_get_sec_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: ssid =%s\n", pnetwork->network.Ssid.Ssid)); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_get_bcn_info: wpa_len =%d rsn_len =%d\n", wpa_len, rsn_len)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.Ssid.Ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: ssid =%s\n", __func__, pnetwork->network.Ssid.Ssid)); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s: wpa_len =%d rsn_len =%d\n", __func__, wpa_len, rsn_len)); if (rsn_len > 0) { pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c index 767928a2cbb4..2183c613e61b 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c @@ -207,7 +207,7 @@ release_mlme_lock: exit: RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, - ("rtw_set_802_11_bssid: status=%d\n", status)); + ("%s: status=%d\n", __func__, status)); return status; @@ -316,7 +316,7 @@ release_mlme_lock: exit: RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, - ("-rtw_set_802_11_ssid: status =%d\n", status)); + ("-%s: status =%d\n", __func__, status)); return status; } @@ -418,22 +418,22 @@ u8 rtw_set_802_11_bssid_list_scan(struct adapter *padapter, struct ndis_802_11_s u8 res = true; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+rtw_set_802_11_bssid_list_scan(), fw_state =%x\n", get_fwstate(pmlmepriv))); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("+%s(), fw_state =%x\n", __func__, get_fwstate(pmlmepriv))); - if (padapter == NULL) { + if (!padapter) { res = false; goto exit; } if (!padapter->hw_init_completed) { res = false; - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === rtw_set_802_11_bssid_list_scan:hw_init_completed == false ===\n")); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("\n === %s:hw_init_completed == false ===\n", __func__)); goto exit; } if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)) || (pmlmepriv->LinkDetectInfo.bBusyTraffic)) { /* Scan or linking is in progress, do nothing. */ - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("rtw_set_802_11_bssid_list_scan fail since fw_state = %x\n", get_fwstate(pmlmepriv))); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("%s fail since fw_state = %x\n", __func__, get_fwstate(pmlmepriv))); res = true; if (check_fwstate(pmlmepriv, @@ -473,7 +473,7 @@ u8 rtw_set_802_11_authentication_mode(struct adapter *padapter, enum ndis_802_11 psecuritypriv->ndisauthtype = authmode; RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, - ("rtw_set_802_11_authentication_mode:psecuritypriv->ndisauthtype=%d", + ("%s:psecuritypriv->ndisauthtype=%d", __func__, psecuritypriv->ndisauthtype)); if (psecuritypriv->ndisauthtype > 3) diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index 1cd49e292804..8d49e3047201 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -790,7 +790,7 @@ void rtw_indicate_connect(struct adapter *padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect\n")); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+%s\n", __func__)); pmlmepriv->to_join = false; @@ -806,7 +806,7 @@ void rtw_indicate_connect(struct adapter *padapter) rtw_set_scan_deny(padapter, 3000); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect: fw_state=0x%08x\n", get_fwstate(pmlmepriv))); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-%s: fw_state=0x%08x\n", __func__, get_fwstate(pmlmepriv))); } /* @@ -897,7 +897,7 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str * Commented by Albert 2012/07/21 * When doing the WPS, the wps_ie_len won't equal to 0 * And the Wi-Fi driver shouldn't allow the data - * packet to be tramsmitted. + * packet to be transmitted. */ if (padapter->securitypriv.wps_ie_len != 0) { psta->ieee8021x_blocked = true; @@ -1371,7 +1371,7 @@ void _rtw_join_timeout_handler (struct timer_list *t) } /* - * rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey + * rtw_scan_timeout_handler - Timeout/Failure handler for CMD SiteSurvey * @adapter: pointer to struct adapter structure */ void rtw_scan_timeout_handler (struct timer_list *t) @@ -1756,7 +1756,7 @@ int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_ uint ndissecuritytype = psecuritypriv->ndisencryptstatus; RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, - ("+rtw_restruct_sec_ie: ndisauthmode=%d ndissecuritytype=%d\n", + ("+%s: ndisauthmode=%d ndissecuritytype=%d\n", __func__, ndisauthmode, ndissecuritytype)); /* copy fixed ie only */ @@ -1983,7 +1983,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len) if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) return; - DBG_88E("+rtw_update_ht_cap()\n"); + DBG_88E("+%s()\n", __func__); /* maybe needs check if ap supports rx ampdu. */ if ((!phtpriv->ampdu_enable) && (pregistrypriv->ampdu_enable == 1)) { @@ -2057,7 +2057,7 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1; if (issued == 0) { - DBG_88E("rtw_issue_addbareq_cmd, p=%d\n", priority); + DBG_88E("%s, p=%d\n", __func__, priority); psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); rtw_addbareq_cmd(padapter, (u8)priority, pattrib->ra); } diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index bcb6919bb7d5..19266cf1edbd 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -163,13 +163,13 @@ struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) struct xmit_buf *pxmitbuf; pmgntframe = rtw_alloc_xmitframe(pxmitpriv); - if (pmgntframe == NULL) { + if (!pmgntframe) { DBG_88E("%s, alloc xmitframe fail\n", __func__); return NULL; } pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); - if (pxmitbuf == NULL) { + if (!pxmitbuf) { DBG_88E("%s, alloc xmitbuf fail\n", __func__); rtw_free_xmitframe(pxmitpriv, pmgntframe); return NULL; @@ -332,7 +332,7 @@ static void issue_beacon(struct adapter *padapter, int timeout_ms) u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) { + if (!pmgntframe) { DBG_88E("%s, alloc mgnt frame fail\n", __func__); return; } @@ -478,7 +478,7 @@ static void issue_probersp(struct adapter *padapter, unsigned char *da) unsigned int rate_len; pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) { + if (!pmgntframe) { DBG_88E("%s, alloc mgnt frame fail\n", __func__); return; } @@ -623,10 +623,10 @@ static int issue_probereq(struct adapter *padapter, int bssrate_len = 0; u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+issue_probereq\n")); + RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+%s\n", __func__)); pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) + if (!pmgntframe) goto exit; /* update attribute */ @@ -912,7 +912,7 @@ static void issue_asocrsp(struct adapter *padapter, unsigned short status, DBG_88E("%s\n", __func__); pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) + if (!pmgntframe) return; /* update attribute */ @@ -1039,7 +1039,7 @@ static void issue_assocreq(struct adapter *padapter) struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network); pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) + if (!pmgntframe) goto exit; /* update attribute */ @@ -1133,7 +1133,7 @@ static void issue_assocreq(struct adapter *padapter) /* RSN */ p = rtw_get_ie((pmlmeinfo->network.IEs + sizeof(struct ndis_802_11_fixed_ie)), _RSN_IE_2_, &ie_len, (pmlmeinfo->network.IELength - sizeof(struct ndis_802_11_fixed_ie))); - if (p != NULL) + if (p) pframe = rtw_set_ie(pframe, _RSN_IE_2_, ie_len, (p + 2), &(pattrib->pktlen)); /* HT caps */ @@ -1221,7 +1221,7 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da, pnetwork = &(pmlmeinfo->network); pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) + if (!pmgntframe) goto exit; /* update attribute */ @@ -1338,7 +1338,7 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, DBG_88E("%s\n", __func__); pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) + if (!pmgntframe) goto exit; /* update attribute */ @@ -1584,7 +1584,7 @@ static void issue_action_BA(struct adapter *padapter, unsigned char *raddr, DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status); pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) + if (!pmgntframe) return; /* update attribute */ @@ -1632,7 +1632,7 @@ static void issue_action_BA(struct adapter *padapter, unsigned char *raddr, &pattrib->pktlen); psta = rtw_get_stainfo(pstapriv, raddr); - if (psta != NULL) { + if (psta) { start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1; DBG_88E("BA_starting_seqctrl=%d for TID=%d\n", start_seq, status & 0x07); @@ -1743,7 +1743,7 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter) action = ACT_PUBLIC_BSSCOEXIST; pmgntframe = alloc_mgtxmitframe(pxmitpriv); - if (pmgntframe == NULL) + if (!pmgntframe) return; /* update attribute */ @@ -2091,7 +2091,7 @@ static u8 collect_bss_info(struct adapter *padapter, /* checking SSID */ p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset); - if (p == NULL) { + if (!p) { DBG_88E("marc: cannot find SSID for survey event\n"); return _FAIL; } @@ -2122,7 +2122,7 @@ static u8 collect_bss_info(struct adapter *padapter, } p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); - if (p != NULL) { + if (p) { if (len > (NDIS_802_11_LENGTH_RATES_EX-i)) { DBG_88E("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len); return _FAIL; @@ -2253,7 +2253,7 @@ static void start_create_ibss(struct adapter *padapter) pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; } } else { - DBG_88E("start_create_ibss, invalid cap:%x\n", caps); + DBG_88E("%s, invalid cap:%x\n", __func__, caps); return; } } @@ -2568,7 +2568,7 @@ static unsigned int OnProbeReq(struct adapter *padapter, len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); /* check (wildcard) SSID */ - if (p != NULL) { + if (p) { if ((ielen != 0 && memcmp((void *)(p+2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) || (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) return _SUCCESS; @@ -2705,7 +2705,7 @@ static unsigned int OnAuth(struct adapter *padapter, if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) return _FAIL; - DBG_88E("+OnAuth\n"); + DBG_88E("+%s\n", __func__); sa = GetAddr2Ptr(pframe); @@ -2735,11 +2735,11 @@ static unsigned int OnAuth(struct adapter *padapter, } pstat = rtw_get_stainfo(pstapriv, sa); - if (pstat == NULL) { + if (!pstat) { /* allocate a new one */ DBG_88E("going to alloc stainfo for sa=%pM\n", sa); pstat = rtw_alloc_stainfo(pstapriv, sa); - if (pstat == NULL) { + if (!pstat) { DBG_88E(" Exceed the upper limit of supported clients...\n"); status = _STATS_UNABLE_HANDLE_STA_; goto auth_fail; @@ -2973,7 +2973,7 @@ static unsigned int OnAssocReq(struct adapter *padapter, } pstat = rtw_get_stainfo(pstapriv, GetAddr2Ptr(pframe)); - if (pstat == NULL) { + if (!pstat) { status = _RSON_CLS2_; goto asoc_class2_error; } @@ -3014,7 +3014,7 @@ static unsigned int OnAssocReq(struct adapter *padapter, /* checking SSID */ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); - if (p == NULL) + if (!p) status = _STATS_FAILURE_; if (ie_len == 0) { /* broadcast ssid, however it is not allowed in assocreq */ @@ -3122,7 +3122,7 @@ static unsigned int OnAssocReq(struct adapter *padapter, goto OnAssocReqFail; pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); - if (wpa_ie == NULL) { + if (!wpa_ie) { if (elems.wps_ie) { DBG_88E("STA included WPS IE in " "(Re)Association Request - assume WPS is " @@ -3653,7 +3653,7 @@ static unsigned int OnAction_back(struct adapter *padapter, addr = GetAddr2Ptr(pframe); psta = rtw_get_stainfo(pstapriv, addr); - if (psta == NULL) + if (!psta) return _SUCCESS; frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr)); @@ -4144,13 +4144,13 @@ void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame) struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe)); RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, - ("+mgt_dispatcher: type(0x%x) subtype(0x%x)\n", + ("+%s: type(0x%x) subtype(0x%x)\n", __func__, (unsigned int)GetFrameType(pframe), (unsigned int)GetFrameSubType(pframe))); if (GetFrameType(pframe) != WIFI_MGT_TYPE) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, - ("mgt_dispatcher: type(0x%x) error!\n", + ("%s: type(0x%x) error!\n", __func__, (unsigned int)GetFrameType(pframe))); return; } @@ -4170,7 +4170,7 @@ void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame) } ptable += index; - if (psta != NULL) { + if (psta) { if (GetRetry(pframe)) { if (precv_frame->attrib.seq_num == psta->RxMgmtFrameSeqNum) { @@ -4355,7 +4355,7 @@ void report_join_res(struct adapter *padapter, int res) pjoinbss_evt->network.join_res = res; pjoinbss_evt->network.aid = res; - DBG_88E("report_join_res(%d)\n", res); + DBG_88E("%s(%d)\n", __func__, res); rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network); @@ -4415,7 +4415,7 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, pdel_sta_evt->mac_id = mac_id; - DBG_88E("report_del_sta_event: delete STA, mac_id =%d\n", mac_id); + DBG_88E("%s: delete STA, mac_id =%d\n", __func__, mac_id); rtw_enqueue_cmd(pcmdpriv, pcmd_obj); } @@ -4460,7 +4460,7 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, ether_addr_copy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr); padd_sta_evt->cam_id = cam_idx; - DBG_88E("report_add_sta_event: add STA\n"); + DBG_88E("%s: add STA\n", __func__); rtw_enqueue_cmd(pcmdpriv, pcmd_obj); } @@ -4702,7 +4702,7 @@ void linked_status_chk(struct adapter *padapter) rx_chk_limit = 4; psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); - if (psta != NULL) { + if (psta) { bool is_p2p_enable = false; if (!chk_ap_is_alive(padapter, psta)) @@ -4782,7 +4782,7 @@ void linked_status_chk(struct adapter *padapter) if (pmlmeinfo->FW_sta_info[i].status == 1) { psta = pmlmeinfo->FW_sta_info[i].psta; - if (psta == NULL) + if (!psta) continue; if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta)) { if (pmlmeinfo->FW_sta_info[i].retry < 3) { @@ -4852,7 +4852,7 @@ void link_timer_hdl(struct timer_list *t) struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { - DBG_88E("link_timer_hdl:no beacon while connecting\n"); + DBG_88E("%s:no beacon while connecting\n", __func__); pmlmeinfo->state = WIFI_FW_NULL_STATE; report_join_res(padapter, -3); } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) { @@ -4863,7 +4863,7 @@ void link_timer_hdl(struct timer_list *t) return; } - DBG_88E("link_timer_hdl: auth timeout and try again\n"); + DBG_88E("%s: auth timeout and try again\n", __func__); pmlmeinfo->auth_seq = 1; issue_auth(padapter, NULL, 0); set_link_timer(pmlmeext, REAUTH_TO); @@ -4875,7 +4875,7 @@ void link_timer_hdl(struct timer_list *t) return; } - DBG_88E("link_timer_hdl: assoc timeout and try again\n"); + DBG_88E("%s: assoc timeout and try again\n", __func__); issue_assocreq(padapter); set_link_timer(pmlmeext, REASSOC_TO); } diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 6506a1587df0..05936a45eb93 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -23,6 +23,7 @@ #include <mon.h> #include <wifi.h> #include <linux/vmalloc.h> +#include <net/lib80211.h> #define ETHERNET_HEADER_SIZE 14 /* Ethernet Header Length */ #define LLC_HEADER_SIZE 6 /* LLC Header Length */ @@ -220,31 +221,20 @@ u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) static int recvframe_chkmic(struct adapter *adapter, struct recv_frame *precvframe) { - int i, res = _SUCCESS; - u32 datalen; - u8 miccode[8]; - u8 bmic_err = false, brpt_micerror = true; - u8 *pframe, *payload, *pframemic; - u8 *mickey; - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &precvframe->attrib; - struct security_priv *psecuritypriv = &adapter->securitypriv; - - struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - - stainfo = rtw_get_stainfo(&adapter->stapriv, &prxattrib->ta[0]); + int res = _SUCCESS; + struct rx_pkt_attrib *prxattrib = &precvframe->attrib; + struct sta_info *stainfo = rtw_get_stainfo(&adapter->stapriv, prxattrib->ta); if (prxattrib->encrypt == _TKIP_) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - ("\n %s: prxattrib->encrypt==_TKIP_\n", __func__)); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - ("\n %s: da=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", - __func__, prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], - prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5])); - - /* calculate mic code */ - if (stainfo != NULL) { + if (stainfo) { + int key_idx; + const int iv_len = 8, icv_len = 4, key_length = 32; + struct sk_buff *skb = precvframe->pkt; + u8 key[32], iv[8], icv[4], *pframe = skb->data; + void *crypto_private = NULL; + struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("TKIP"), "lib80211_crypt_tkip"); + struct security_priv *psecuritypriv = &adapter->securitypriv; + if (IS_MCAST(prxattrib->ra)) { if (!psecuritypriv) { res = _FAIL; @@ -253,115 +243,58 @@ static int recvframe_chkmic(struct adapter *adapter, DBG_88E("\n %s: didn't install group key!!!!!!!!!!\n", __func__); goto exit; } - mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; - - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - ("\n %s: bcmc key\n", __func__)); + key_idx = prxattrib->key_index; + memcpy(key, psecuritypriv->dot118021XGrpKey[key_idx].skey, 16); + memcpy(key + 16, psecuritypriv->dot118021XGrprxmickey[key_idx].skey, 16); } else { - mickey = &stainfo->dot11tkiprxmickey.skey[0]; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, - ("\n %s: unicast key\n", __func__)); + key_idx = 0; + memcpy(key, stainfo->dot118021x_UncstKey.skey, 16); + memcpy(key + 16, stainfo->dot11tkiprxmickey.skey, 16); } - /* icv_len included the mic code */ - datalen = precvframe->pkt->len-prxattrib->hdrlen - - prxattrib->iv_len-prxattrib->icv_len-8; - pframe = precvframe->pkt->data; - payload = pframe+prxattrib->hdrlen+prxattrib->iv_len; - - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len)); - rtw_seccalctkipmic(mickey, pframe, payload, datalen, &miccode[0], - (unsigned char)prxattrib->priority); /* care the length of the data */ + if (!crypto_ops) { + res = _FAIL; + goto exit_lib80211_tkip; + } - pframemic = payload+datalen; + memcpy(iv, pframe + prxattrib->hdrlen, iv_len); + memcpy(icv, pframe + skb->len - icv_len, icv_len); + memmove(pframe + iv_len, pframe, prxattrib->hdrlen); - bmic_err = false; + skb_pull(skb, iv_len); + skb_trim(skb, skb->len - icv_len); - for (i = 0; i < 8; i++) { - if (miccode[i] != *(pframemic+i)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, - ("%s: miccode[%d](%02x)!=*(pframemic+%d)(%02x) ", - __func__, i, miccode[i], i, *(pframemic + i))); - bmic_err = true; - } + crypto_private = crypto_ops->init(key_idx); + if (!crypto_private) { + res = _FAIL; + goto exit_lib80211_tkip; + } + if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) { + res = _FAIL; + goto exit_lib80211_tkip; + } + if (crypto_ops->decrypt_msdu(skb, key_idx, prxattrib->hdrlen, crypto_private)) { + res = _FAIL; + goto exit_lib80211_tkip; } - if (bmic_err) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, - ("\n *(pframemic-8)-*(pframemic-1)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", - *(pframemic-8), *(pframemic-7), *(pframemic-6), - *(pframemic-5), *(pframemic-4), *(pframemic-3), - *(pframemic-2), *(pframemic-1))); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, - ("\n *(pframemic-16)-*(pframemic-9)=0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n", - *(pframemic-16), *(pframemic-15), *(pframemic-14), - *(pframemic-13), *(pframemic-12), *(pframemic-11), - *(pframemic-10), *(pframemic-9))); - { - uint i; + memmove(pframe, pframe + iv_len, prxattrib->hdrlen); + skb_push(skb, iv_len); + skb_put(skb, icv_len); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, - ("\n ======demp packet (len=%d)======\n", - precvframe->pkt->len)); - for (i = 0; i < precvframe->pkt->len; i += 8) { - RT_TRACE(_module_rtl871x_recv_c_, - _drv_err_, - ("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x", - *(precvframe->pkt->data+i), - *(precvframe->pkt->data+i+1), - *(precvframe->pkt->data+i+2), - *(precvframe->pkt->data+i+3), - *(precvframe->pkt->data+i+4), - *(precvframe->pkt->data+i+5), - *(precvframe->pkt->data+i+6), - *(precvframe->pkt->data+i+7))); - } - RT_TRACE(_module_rtl871x_recv_c_, - _drv_err_, - ("\n ====== demp packet end [len=%d]======\n", - precvframe->pkt->len)); - RT_TRACE(_module_rtl871x_recv_c_, - _drv_err_, - ("\n hrdlen=%d,\n", - prxattrib->hdrlen)); - } + memcpy(pframe + prxattrib->hdrlen, iv, iv_len); + memcpy(pframe + skb->len - icv_len, icv, icv_len); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, - ("ra=0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x psecuritypriv->binstallGrpkey=%d ", - prxattrib->ra[0], prxattrib->ra[1], prxattrib->ra[2], - prxattrib->ra[3], prxattrib->ra[4], prxattrib->ra[5], psecuritypriv->binstallGrpkey)); - - /* double check key_index for some timing issue , */ - /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ - if ((IS_MCAST(prxattrib->ra) == true) && (prxattrib->key_index != pmlmeinfo->key_index)) - brpt_micerror = false; - - if ((prxattrib->bdecrypted) && (brpt_micerror)) { - rtw_handle_tkip_mic_err(adapter, (u8)IS_MCAST(prxattrib->ra)); - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); - DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); - } else { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted=%d ", prxattrib->bdecrypted)); - DBG_88E(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); - } - res = _FAIL; - } else { - /* mic checked ok */ - if ((!psecuritypriv->bcheck_grpkey) && (IS_MCAST(prxattrib->ra))) { - psecuritypriv->bcheck_grpkey = true; - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("psecuritypriv->bcheck_grpkey = true")); - } - } +exit_lib80211_tkip: + if (crypto_ops && crypto_private) + crypto_ops->deinit(crypto_private); } else { RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("%s: rtw_get_stainfo==NULL!!!\n", __func__)); } - - skb_trim(precvframe->pkt, precvframe->pkt->len - 8); } exit: - return res; } @@ -404,7 +337,7 @@ static struct recv_frame *decryptor(struct adapter *padapter, switch (prxattrib->encrypt) { case _WEP40_: case _WEP104_: - rtw_wep_decrypt(padapter, (u8 *)precv_frame); + res = rtw_wep_decrypt(padapter, (u8 *)precv_frame); break; case _TKIP_: res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); @@ -454,7 +387,7 @@ static struct recv_frame *portctrl(struct adapter *adapter, prtnframe = NULL; - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n", adapter->securitypriv.dot11AuthAlgrthm)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:adapter->securitypriv.dot11AuthAlgrthm=%d\n", __func__, adapter->securitypriv.dot11AuthAlgrthm)); if (auth_alg == 2) { /* get ether_type */ @@ -465,7 +398,7 @@ static struct recv_frame *portctrl(struct adapter *adapter, if ((psta != NULL) && (psta->ieee8021x_blocked)) { /* blocked */ /* only accept EAPOL frame */ - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==1\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:psta->ieee8021x_blocked==1\n", __func__)); if (ether_type == eapol_type) { prtnframe = precv_frame; @@ -477,23 +410,23 @@ static struct recv_frame *portctrl(struct adapter *adapter, } else { /* allowed */ /* check decryption status, and decrypt the frame if needed */ - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==0\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:psta->ieee8021x_blocked==0\n", __func__)); RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - ("portctrl:precv_frame->hdr.attrib.privacy=%x\n", - precv_frame->attrib.privacy)); + ("%s:precv_frame->hdr.attrib.privacy=%x\n", + __func__, precv_frame->attrib.privacy)); if (pattrib->bdecrypted == 0) - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("portctrl:prxstat->decrypted=%x\n", pattrib->bdecrypted)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s:prxstat->decrypted=%x\n", __func__, pattrib->bdecrypted)); prtnframe = precv_frame; /* check is the EAPOL frame or not (Rekey) */ if (ether_type == eapol_type) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type==0x888e\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########%s:ether_type==0x888e\n", __func__)); /* check Rekey */ prtnframe = precv_frame; } else { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type=0x%04x\n", ether_type)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########%s:ether_type=0x%04x\n", __func__, ether_type)); } } } else { @@ -512,14 +445,14 @@ static int recv_decache(struct recv_frame *precv_frame, u8 bretry, (precv_frame->attrib.frag_num & 0xf); if (tid > 15) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", __func__, seq_ctrl, tid)); return _FAIL; } if (1) {/* if (bretry) */ if (seq_ctrl == prxcache->tid_rxseq[tid]) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", seq_ctrl, tid, prxcache->tid_rxseq[tid])); + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s, seq_ctrl=0x%x, tid=0x%x, tid_rxseq=0x%x\n", __func__, seq_ctrl, tid, prxcache->tid_rxseq[tid])); return _FAIL; } @@ -718,7 +651,7 @@ int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame, *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */ if (*psta == NULL) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under %s ; drop pkt\n", __func__)); ret = _FAIL; goto exit; } @@ -754,7 +687,7 @@ static int ap2sta_data_frame( /* da should be for me */ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - (" ap2sta_data_frame: compare DA fail; DA=%pM\n", (pattrib->dst))); + (" %s: compare DA fail; DA=%pM\n", __func__, (pattrib->dst))); ret = _FAIL; goto exit; } @@ -764,7 +697,7 @@ static int ap2sta_data_frame( !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - (" ap2sta_data_frame: compare BSSID fail ; BSSID=%pM\n", (pattrib->bssid))); + (" %s: compare BSSID fail ; BSSID=%pM\n", __func__, (pattrib->bssid))); RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid=%pM\n", (mybssid))); if (!bmcast) { @@ -1009,10 +942,10 @@ static int validate_recv_mgnt_frame(struct adapter *padapter, { struct sta_info *psta; - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+validate_recv_mgnt_frame\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+%s\n", __func__)); precv_frame = recvframe_chk_defrag(padapter, precv_frame); - if (precv_frame == NULL) { + if (!precv_frame) { RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("%s: fragment packet\n", __func__)); return _SUCCESS; @@ -1060,7 +993,7 @@ static int validate_recv_data_frame(struct adapter *adapter, psa = get_sa(ptr); pbssid = get_hdr_bssid(ptr); - if (pbssid == NULL) { + if (!pbssid) { ret = _FAIL; goto exit; } @@ -1102,7 +1035,7 @@ static int validate_recv_data_frame(struct adapter *adapter, else if (ret == RTW_RX_HANDLED) goto exit; - if (psta == NULL) { + if (!psta) { RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n")); ret = _FAIL; goto exit; @@ -1141,7 +1074,7 @@ static int validate_recv_data_frame(struct adapter *adapter, } if (pattrib->privacy) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("validate_recv_data_frame:pattrib->privacy=%x\n", pattrib->privacy)); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s:pattrib->privacy=%x\n", __func__, pattrib->privacy)); RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n ^^^^^^^^^^^IS_MCAST(pattrib->ra(0x%02x))=%d^^^^^^^^^^^^^^^6\n", pattrib->ra[0], IS_MCAST(pattrib->ra))); GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra)); @@ -1436,7 +1369,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, psta_addr = pfhdr->attrib.ta; psta = rtw_get_stainfo(pstapriv, psta_addr); - if (psta == NULL) { + if (!psta) { u8 type = GetFrameType(pfhdr->pkt->data); if (type != WIFI_DATA_TYPE) { @@ -1455,7 +1388,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, if (ismfrag == 1) { /* 0~(n-1) fragment frame */ /* enqueue to defraf_g */ - if (pdefrag_q != NULL) { + if (pdefrag_q) { if (fragnum == 0) { /* the first fragment */ if (!list_empty(&pdefrag_q->queue)) @@ -1482,7 +1415,7 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, if ((ismfrag == 0) && (fragnum != 0)) { /* the last fragment frame */ /* enqueue the last fragment */ - if (pdefrag_q != NULL) { + if (pdefrag_q) { phead = get_list_head(pdefrag_q); list_add_tail(&pfhdr->list, phead); @@ -1714,8 +1647,8 @@ static int recv_indicatepkts_in_order(struct adapter *padapter, struct recv_reor if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, - ("recv_indicatepkts_in_order: indicate=%d seq=%d amsdu=%d\n", - preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu)); + ("%s: indicate=%d seq=%d amsdu=%d\n", + __func__, preorder_ctrl->indicate_seq, pattrib->seq_num, pattrib->amsdu)); plist = plist->next; list_del_init(&(prframe->list)); @@ -1762,7 +1695,7 @@ static int recv_indicatepkt_reorder(struct adapter *padapter, (pattrib->ack_policy != 0)) { if ((!padapter->bDriverStopped) && (!padapter->bSurpriseRemoved)) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ recv_indicatepkt_reorder -recv_func recv_indicatepkt\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s -recv_func recv_indicatepkt\n", __func__)); rtw_recv_indicatepkt(padapter, prframe); return _SUCCESS; @@ -1792,7 +1725,7 @@ static int recv_indicatepkt_reorder(struct adapter *padapter, spin_lock_bh(&ppending_recvframe_queue->lock); RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, - ("recv_indicatepkt_reorder: indicate=%d seq=%d\n", + ("%s: indicate=%d seq=%d\n", __func__, preorder_ctrl->indicate_seq, pattrib->seq_num)); /* s2. check if winstart_b(indicate_seq) needs to been updated */ @@ -1884,10 +1817,10 @@ static int process_recv_indicatepkts(struct adapter *padapter, if ((!padapter->bDriverStopped) && (!padapter->bSurpriseRemoved)) { /* indicate this recv_frame */ - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func recv_indicatepkt\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s- recv_func recv_indicatepkt\n", __func__)); rtw_recv_indicatepkt(padapter, prframe); } else { - RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ process_recv_indicatepkts- recv_func free_indicatepkt\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("@@@@ %s- recv_func free_indicatepkt\n", __func__)); RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_func:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); retval = _FAIL; @@ -1928,20 +1861,20 @@ static int recv_func_posthandle(struct adapter *padapter, LedControl8188eu(padapter, LED_CTL_RX); prframe = decryptor(padapter, prframe); - if (prframe == NULL) { + if (!prframe) { RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("decryptor: drop pkt\n")); ret = _FAIL; goto _recv_data_drop; } prframe = recvframe_chk_defrag(padapter, prframe); - if (prframe == NULL) { + if (!prframe) { RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chk_defrag: drop pkt\n")); goto _recv_data_drop; } prframe = portctrl(padapter, prframe); - if (prframe == NULL) { + if (!prframe) { RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("portctrl: drop pkt\n")); ret = _FAIL; goto _recv_data_drop; @@ -2012,7 +1945,7 @@ s32 rtw_recv_entry(struct recv_frame *precvframe) ret = recv_func(padapter, precvframe); if (ret == _FAIL) { - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("rtw_recv_entry: recv_func return fail!!!\n")); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("%s: recv_func return fail!!!\n", __func__)); goto _recv_entry_drop; } diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index 5b1ef229df2a..bfe0b217e679 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -18,6 +18,7 @@ #include <drv_types.h> #include <wifi.h> #include <osdep_intf.h> +#include <net/lib80211.h> /* WEP related ===== */ @@ -195,48 +196,57 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) } -void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) +int rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) { - /* exclude ICV */ - u8 crc[4]; - struct arc4context mycontext; - int length; - u32 keylength; - u8 *pframe, *payload, *iv, wepkey[16]; - u8 keyindex; struct rx_pkt_attrib *prxattrib = &(((struct recv_frame *)precvframe)->attrib); - struct security_priv *psecuritypriv = &padapter->securitypriv; + if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) { + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt; + u8 *pframe = skb->data; + void *crypto_private = NULL; + int status = _SUCCESS; + const int keyindex = prxattrib->key_index; + struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("WEP"), "lib80211_crypt_wep"); + char iv[4], icv[4]; + + if (!crypto_ops) { + status = _FAIL; + goto exit; + } - pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data; + memcpy(iv, pframe + prxattrib->hdrlen, 4); + memcpy(icv, pframe + skb->len - 4, 4); - /* start to decrypt recvframe */ - if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) { - iv = pframe+prxattrib->hdrlen; - keyindex = prxattrib->key_index; - keylength = psecuritypriv->dot11DefKeylen[keyindex]; - memcpy(&wepkey[0], iv, 3); - memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength); - length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len; - - payload = pframe+prxattrib->iv_len+prxattrib->hdrlen; - - /* decrypt payload include icv */ - arcfour_init(&mycontext, wepkey, 3+keylength); - arcfour_encrypt(&mycontext, payload, payload, length); - - /* calculate icv and compare the icv */ - *((__le32 *)crc) = getcrc32(payload, length - 4); - - if (crc[3] != payload[length-1] || - crc[2] != payload[length-2] || - crc[1] != payload[length-3] || - crc[0] != payload[length-4]) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, - ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n", - &crc, &payload[length-4])); + crypto_private = crypto_ops->init(keyindex); + if (!crypto_private) { + status = _FAIL; + goto exit; } + if (crypto_ops->set_key(psecuritypriv->dot11DefKey[keyindex].skey, + psecuritypriv->dot11DefKeylen[keyindex], NULL, crypto_private) < 0) { + status = _FAIL; + goto exit; + } + if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) { + status = _FAIL; + goto exit; + } + + memmove(pframe, pframe + 4, prxattrib->hdrlen); + skb_push(skb, 4); + skb_put(skb, 4); + + memcpy(pframe + prxattrib->hdrlen, iv, 4); + memcpy(pframe + skb->len - 4, icv, 4); + +exit: + if (crypto_ops && crypto_private) + crypto_ops->deinit(crypto_private); + return status; } + + return _FAIL; } /* 3 ===== TKIP related ===== */ @@ -593,7 +603,7 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); if (stainfo != NULL) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo!= NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__)); if (IS_MCAST(pattrib->ra)) prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; @@ -633,78 +643,78 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) } } } else { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo==NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo==NULL!!!\n", __func__)); res = _FAIL; } } return res; } -/* The hlen isn't include the IV */ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) -{ /* exclude ICV */ - u16 pnl; - u32 pnh; - u8 rc4key[16]; - u8 ttkey[16]; - u8 crc[4]; - struct arc4context mycontext; - int length; - - u8 *pframe, *payload, *iv, *prwskey; - union pn48 dot11txpn; - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - u32 res = _SUCCESS; - - - pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data; +{ + struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; + u32 res = _SUCCESS; /* 4 start to decrypt recvframe */ if (prxattrib->encrypt == _TKIP_) { - stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); - if (stainfo != NULL) { + struct sta_info *stainfo = rtw_get_stainfo(&padapter->stapriv, prxattrib->ta); + + if (stainfo) { + int key_idx; + const int iv_len = 8, icv_len = 4, key_length = 32; + void *crypto_private = NULL; + struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt; + u8 key[32], iv[8], icv[4], *pframe = skb->data; + struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("TKIP"), "lib80211_crypt_tkip"); + struct security_priv *psecuritypriv = &padapter->securitypriv; + if (IS_MCAST(prxattrib->ra)) { if (!psecuritypriv->binstallGrpkey) { res = _FAIL; DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); goto exit; } - prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; + key_idx = prxattrib->key_index; + memcpy(key, psecuritypriv->dot118021XGrpKey[key_idx].skey, 16); + memcpy(key + 16, psecuritypriv->dot118021XGrprxmickey[key_idx].skey, 16); } else { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo!= NULL!!!\n")); - prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + key_idx = 0; + memcpy(key, stainfo->dot118021x_UncstKey.skey, 16); + memcpy(key + 16, stainfo->dot11tkiprxmickey.skey, 16); } - iv = pframe+prxattrib->hdrlen; - payload = pframe+prxattrib->iv_len+prxattrib->hdrlen; - length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len; - - GET_TKIP_PN(iv, dot11txpn); - - pnl = (u16)(dot11txpn.val); - pnh = (u32)(dot11txpn.val>>16); + if (!crypto_ops) { + res = _FAIL; + goto exit_lib80211_tkip; + } - phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh); - phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl); + memcpy(iv, pframe + prxattrib->hdrlen, iv_len); + memcpy(icv, pframe + skb->len - icv_len, icv_len); - /* 4 decrypt payload include icv */ + crypto_private = crypto_ops->init(key_idx); + if (!crypto_private) { + res = _FAIL; + goto exit_lib80211_tkip; + } + if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) { + res = _FAIL; + goto exit_lib80211_tkip; + } + if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) { + res = _FAIL; + goto exit_lib80211_tkip; + } - arcfour_init(&mycontext, rc4key, 16); - arcfour_encrypt(&mycontext, payload, payload, length); + memmove(pframe, pframe + iv_len, prxattrib->hdrlen); + skb_push(skb, iv_len); + skb_put(skb, icv_len); - *((__le32 *)crc) = getcrc32(payload, length-4); + memcpy(pframe + prxattrib->hdrlen, iv, iv_len); + memcpy(pframe + skb->len - icv_len, icv, icv_len); - if (crc[3] != payload[length-1] || - crc[2] != payload[length-2] || - crc[1] != payload[length-3] || - crc[0] != payload[length-4]) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, - ("rtw_wep_decrypt:icv error crc (%4ph)!=payload (%4ph)\n", - &crc, &payload[length-4])); - res = _FAIL; - } +exit_lib80211_tkip: + if (crypto_ops && crypto_private) + crypto_ops->deinit(crypto_private); } else { RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo==NULL!!!\n")); res = _FAIL; @@ -1235,8 +1245,8 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) else stainfo = rtw_get_stainfo(&padapter->stapriv, &pattrib->ra[0]); - if (stainfo != NULL) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n")); + if (stainfo) { + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__)); if (IS_MCAST(pattrib->ra)) prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; @@ -1256,7 +1266,7 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) } } } else{ - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo==NULL!!!\n", __func__)); res = _FAIL; } } @@ -1265,217 +1275,24 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) return res; } -static int aes_decipher(u8 *key, uint hdrlen, - u8 *pframe, uint plen) +u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) { - static u8 message[MAX_MSG_SIZE]; - uint qc_exists, a4_exists, i, j, payload_remainder, - num_blocks, payload_index; - int res = _SUCCESS; - - u8 pn_vector[6]; - u8 mic_iv[16]; - u8 mic_header1[16]; - u8 mic_header2[16]; - u8 ctr_preload[16]; - - /* Intermediate Buffers */ - u8 chain_buffer[16]; - u8 aes_out[16]; - u8 padded_buffer[16]; - u8 mic[8]; - -/* uint offset = 0; */ - uint frtype = GetFrameType(pframe); - uint frsubtype = GetFrameSubType(pframe); - frsubtype >>= 4; - - memset(mic_iv, 0, 16); - memset(mic_header1, 0, 16); - memset(mic_header2, 0, 16); - memset(ctr_preload, 0, 16); - memset(chain_buffer, 0, 16); - memset(aes_out, 0, 16); - memset(padded_buffer, 0, 16); - - /* start to decrypt the payload */ - - num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */ - - payload_remainder = (plen-8) % 16; - - pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen+1]; - pn_vector[2] = pframe[hdrlen+4]; - pn_vector[3] = pframe[hdrlen+5]; - pn_vector[4] = pframe[hdrlen+6]; - pn_vector[5] = pframe[hdrlen+7]; - - if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) - a4_exists = 0; - else - a4_exists = 1; - - if ((frtype == WIFI_DATA_CFACK) || (frtype == WIFI_DATA_CFPOLL) || - (frtype == WIFI_DATA_CFACKPOLL)) { - qc_exists = 1; - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - } else if ((frsubtype == 0x08) || (frsubtype == 0x09) || - (frsubtype == 0x0a) || (frsubtype == 0x0b)) { - if (hdrlen != WLAN_HDR_A3_QOS_LEN) - hdrlen += 2; - qc_exists = 1; - } else { - qc_exists = 0; - } - - /* now, decrypt pframe with hdrlen offset and plen long */ - - payload_index = hdrlen + 8; /* 8 is for extiv */ - - for (i = 0; i < num_blocks; i++) { - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, i+1); - - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); - - for (j = 0; j < 16; j++) - pframe[payload_index++] = chain_buffer[j]; - } - - if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ - /* encrypt it and copy the unpadded part back */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, num_blocks+1); - - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = pframe[payload_index+j]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < payload_remainder; j++) - pframe[payload_index++] = chain_buffer[j]; - } - - /* start to calculate the mic */ - if ((hdrlen+plen+8) <= MAX_MSG_SIZE) - memcpy(message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */ - - pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen+1]; - pn_vector[2] = pframe[hdrlen+4]; - pn_vector[3] = pframe[hdrlen+5]; - pn_vector[4] = pframe[hdrlen+6]; - pn_vector[5] = pframe[hdrlen+7]; - construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector); - - construct_mic_header1(mic_header1, hdrlen, message); - construct_mic_header2(mic_header2, message, a4_exists, qc_exists); - - payload_remainder = (plen-8) % 16; - num_blocks = (plen-8) / 16; - - /* Find start of payload */ - payload_index = hdrlen + 8; - - /* Calculate MIC */ - aes128k128d(key, mic_iv, aes_out); - bitwise_xor(aes_out, mic_header1, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - bitwise_xor(aes_out, mic_header2, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - - for (i = 0; i < num_blocks; i++) { - bitwise_xor(aes_out, &message[payload_index], chain_buffer); - - payload_index += 16; - aes128k128d(key, chain_buffer, aes_out); - } - - /* Add on the final payload block if it needs padding */ - if (payload_remainder > 0) { - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = message[payload_index++]; - bitwise_xor(aes_out, padded_buffer, chain_buffer); - aes128k128d(key, chain_buffer, aes_out); - } - - for (j = 0 ; j < 8; j++) - mic[j] = aes_out[j]; - - /* Insert MIC into payload */ - for (j = 0; j < 8; j++) - message[payload_index+j] = mic[j]; - - payload_index = hdrlen + 8; - for (i = 0; i < num_blocks; i++) { - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1); - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &message[payload_index], chain_buffer); - for (j = 0; j < 16; j++) - message[payload_index++] = chain_buffer[j]; - } - - if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ - /* encrypt it and copy the unpadded part back */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, num_blocks+1); - - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = message[payload_index+j]; - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < payload_remainder; j++) - message[payload_index++] = chain_buffer[j]; - } - - /* Encrypt the MIC */ - construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0); - - for (j = 0; j < 16; j++) - padded_buffer[j] = 0x00; - for (j = 0; j < 8; j++) - padded_buffer[j] = message[j+hdrlen+8+plen-8]; - - aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, padded_buffer, chain_buffer); - for (j = 0; j < 8; j++) - message[payload_index++] = chain_buffer[j]; - - /* compare the mic */ - for (i = 0; i < 8; i++) { - if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, - ("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n", - i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i])); - DBG_88E("aes_decipher:mic check error mic[%d]: pframe(%x)!=message(%x)\n", - i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]); - res = _FAIL; - } - } - return res; -} - -u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) -{ /* exclude ICV */ - /* Intermediate Buffers */ - int length; - u8 *pframe, *prwskey; /* *payload,*iv */ - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - u32 res = _SUCCESS; + struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib; + u32 res = _SUCCESS; - pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data; /* 4 start to encrypt each fragment */ if (prxattrib->encrypt == _AES_) { - stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); + struct sta_info *stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); + if (stainfo != NULL) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n")); + int key_idx; + const int key_length = 16, iv_len = 8, icv_len = 8; + struct sk_buff *skb = ((struct recv_frame *)precvframe)->pkt; + void *crypto_private = NULL; + u8 *key, *pframe = skb->data; + struct lib80211_crypto_ops *crypto_ops = try_then_request_module(lib80211_get_crypto_ops("CCMP"), "lib80211_crypt_ccmp"); + struct security_priv *psecuritypriv = &padapter->securitypriv; + char iv[8], icv[8]; if (IS_MCAST(prxattrib->ra)) { /* in concurrent we should use sw descrypt in group key, so we remove this message */ @@ -1484,18 +1301,45 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) DBG_88E("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__); goto exit; } - prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; - if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) { - DBG_88E("not match packet_index=%d, install_index=%d\n", - prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); - res = _FAIL; - goto exit; - } + key_idx = psecuritypriv->dot118021XGrpKeyid; + key = psecuritypriv->dot118021XGrpKey[key_idx].skey; } else { - prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + key_idx = 0; + key = stainfo->dot118021x_UncstKey.skey; + } + + if (!crypto_ops) { + res = _FAIL; + goto exit_lib80211_ccmp; } - length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len; - res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); + + memcpy(iv, pframe + prxattrib->hdrlen, iv_len); + memcpy(icv, pframe + skb->len - icv_len, icv_len); + + crypto_private = crypto_ops->init(key_idx); + if (!crypto_private) { + res = _FAIL; + goto exit_lib80211_ccmp; + } + if (crypto_ops->set_key(key, key_length, NULL, crypto_private) < 0) { + res = _FAIL; + goto exit_lib80211_ccmp; + } + if (crypto_ops->decrypt_mpdu(skb, prxattrib->hdrlen, crypto_private)) { + res = _FAIL; + goto exit_lib80211_ccmp; + } + + memmove(pframe, pframe + iv_len, prxattrib->hdrlen); + skb_push(skb, iv_len); + skb_put(skb, icv_len); + + memcpy(pframe + prxattrib->hdrlen, iv, iv_len); + memcpy(pframe + skb->len - icv_len, icv, icv_len); + +exit_lib80211_ccmp: + if (crypto_ops && crypto_private) + crypto_ops->deinit(crypto_private); } else { RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n")); res = _FAIL; diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c index 2fd2a9e2416e..f42aa4e0ddb8 100644 --- a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c @@ -194,9 +194,9 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) _rtw_init_stainfo(psta); memcpy(psta->hwaddr, hwaddr, ETH_ALEN); index = wifi_mac_hash(hwaddr); - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("rtw_alloc_stainfo: index=%x", index)); + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("%s: index=%x", __func__, index)); if (index >= NUM_STA) { - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => rtw_alloc_stainfo: index >= NUM_STA")); + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => %s: index >= NUM_STA", __func__)); psta = NULL; goto exit; } diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index 2db8a5d11c0d..9a130cbf6def 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -715,7 +715,7 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) struct ht_priv *phtpriv = &pmlmepriv->htpriv; u8 *HT_cap = (u8 *)(&pmlmeinfo->HT_caps); - if (pIE == NULL) + if (!pIE) return; if (!phtpriv->ht_option) @@ -755,7 +755,7 @@ void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct ht_priv *phtpriv = &pmlmepriv->htpriv; - if (pIE == NULL) + if (!pIE) return; if (!phtpriv->ht_option) @@ -1534,7 +1534,7 @@ int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_l struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); pIE = (struct ndis_802_11_var_ie *)rtw_get_ie(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len); - if (pIE == NULL) + if (!pIE) return _FAIL; if (ie_len > NDIS_802_11_LENGTH_RATES_EX) return _FAIL; diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c index e8d9858f2942..3c034486346b 100644 --- a/drivers/staging/rtl8188eu/core/rtw_xmit.c +++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c @@ -387,34 +387,27 @@ u8 qos_acm(u8 acm_mask, u8 priority) return change_priority; } -static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) +static void set_qos(struct sk_buff *skb, struct pkt_attrib *pattrib) { - struct ethhdr etherhdr; - struct iphdr ip_hdr; - s32 user_prio = 0; - - _rtw_open_pktfile(ppktfile->pkt, ppktfile); - _rtw_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); - - /* get user_prio from IP hdr */ if (pattrib->ether_type == 0x0800) { - _rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); -/* user_prio = (ntohs(ip_hdr.tos) >> 5) & 0x3; */ - user_prio = ip_hdr.tos >> 5; + struct iphdr ip_hdr; + + skb_copy_bits(skb, ETH_HLEN, &ip_hdr, sizeof(ip_hdr)); + pattrib->priority = ip_hdr.tos >> 5; } else if (pattrib->ether_type == ETH_P_PAE) { /* "When priority processing of data frames is supported, */ /* a STA's SME should send EAPOL-Key frames at the highest priority." */ - user_prio = 7; + pattrib->priority = 7; + } else { + pattrib->priority = 0; } - pattrib->priority = user_prio; pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; pattrib->subtype = WIFI_QOS_DATA_TYPE; } static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct pkt_attrib *pattrib) { - struct pkt_file pktfile; struct sta_info *psta = NULL; struct ethhdr etherhdr; @@ -425,9 +418,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p struct qos_priv *pqospriv = &pmlmepriv->qospriv; int res = _SUCCESS; - - _rtw_open_pktfile(pkt, &pktfile); - _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); + skb_copy_bits(pkt, 0, ðerhdr, ETH_HLEN); pattrib->ether_type = ntohs(etherhdr.h_proto); @@ -448,22 +439,23 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); } - pattrib->pktlen = pktfile.pkt_len; + pattrib->pktlen = pkt->len - ETH_HLEN; if (pattrib->ether_type == ETH_P_IP) { /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ /* to prevent DHCP protocol fail */ u8 tmp[24]; - _rtw_pktfile_read(&pktfile, &tmp[0], 24); + skb_copy_bits(pkt, ETH_HLEN, tmp, 24); + pattrib->dhcp_pkt = 0; - if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ + if (pkt->len > ETH_HLEN + 24 + 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ if (pattrib->ether_type == ETH_P_IP) {/* IP header */ if (((tmp[21] == 68) && (tmp[23] == 67)) || ((tmp[21] == 67) && (tmp[23] == 68))) { /* 68 : UDP BOOTP client */ /* 67 : UDP BOOTP server */ - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== update_attrib: get DHCP Packet\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====================== %s: get DHCP Packet\n", __func__)); /* Use low rate to send DHCP packet. */ pattrib->dhcp_pkt = 1; } @@ -487,7 +479,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p psta = rtw_get_bcmc_stainfo(padapter); } else { psta = rtw_get_stainfo(pstapriv, pattrib->ra); - if (psta == NULL) { /* if we cannot get psta => drrp the pkt */ + if (!psta) { /* if we cannot get psta => drrp the pkt */ RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra: %pM\n", (pattrib->ra))); res = _FAIL; goto exit; @@ -516,10 +508,10 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p if (check_fwstate(pmlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) { if (psta->qos_option) - set_qos(&pktfile, pattrib); + set_qos(pkt, pattrib); } else { if (pqospriv->qos_option) { - set_qos(&pktfile, pattrib); + set_qos(pkt, pattrib); if (pmlmepriv->acm_mask != 0) pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority); @@ -587,16 +579,16 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p } RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, - ("update_attrib: encrypt=%d\n", pattrib->encrypt)); + ("%s: encrypt=%d\n", __func__, pattrib->encrypt)); if (pattrib->encrypt && !psecuritypriv->hw_decrypted) { pattrib->bswenc = true; RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, - ("update_attrib: encrypt=%d bswenc = true\n", + ("%s: encrypt=%d bswenc = true\n", __func__, pattrib->encrypt)); } else { pattrib->bswenc = false; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("update_attrib: bswenc = false\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s: bswenc = false\n", __func__)); } update_attrib_phy_info(pattrib, psta); @@ -630,7 +622,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr if (pattrib->encrypt == _TKIP_) {/* if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_PRIVACY_) */ /* encode mic code */ - if (stainfo != NULL) { + if (stainfo) { u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; @@ -698,11 +690,11 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr } } rtw_secgetmic(&micdata, &mic[0]); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n")); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz=%d!!!\n", pattrib->last_txcmdsz)); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\ + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: before add mic code!!!\n", __func__)); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: pattrib->last_txcmdsz=%d!!!\n", __func__, pattrib->last_txcmdsz)); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: mic[0]=0x%.2x , mic[1]=0x%.2x , mic[2]= 0x%.2x, mic[3]=0x%.2x\n\ mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x , mic[7]= 0x%.2x !!!!\n", - mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7])); + __func__, mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7])); /* add mic code and add the mic code length in last_txcmdsz */ memcpy(payload, &mic[0], 8); @@ -718,7 +710,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr *(payload + curfragnum + 4), *(payload + curfragnum + 5), *(payload + curfragnum + 6), *(payload + curfragnum + 7))); } else { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: rtw_get_stainfo==NULL!!!\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_get_stainfo==NULL!!!\n", __func__)); } } @@ -732,7 +724,7 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi if (pattrib->bswenc) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### xmitframe_swencrypt\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("### %s\n", __func__)); switch (pattrib->encrypt) { case _WEP40_: case _WEP104_: @@ -951,7 +943,6 @@ This sub-routine will perform all the following: */ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct xmit_frame *pxmitframe) { - struct pkt_file pktfile; s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; size_t addr; u8 *pframe, *mem_start; @@ -962,11 +953,11 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct u8 *pbuf_start; s32 bmcst = IS_MCAST(pattrib->ra); s32 res = _SUCCESS; - + size_t remainder = pkt->len - ETH_HLEN; psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); - if (psta == NULL) + if (!psta) return _FAIL; if (pxmitframe->buf_addr == NULL) { @@ -981,15 +972,12 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct mem_start = pbuf_start + hw_hdr_offset; if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n")); - DBG_88E("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__)); + DBG_88E("%s: rtw_make_wlanhdr fail; drop pkt\n", __func__); res = _FAIL; goto exit; } - _rtw_open_pktfile(pkt, &pktfile); - _rtw_pktfile_read(&pktfile, NULL, ETH_HLEN); - frg_inx = 0; frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ @@ -1029,8 +1017,8 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct memcpy(pframe, pattrib->iv, pattrib->iv_len); RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, - ("rtw_xmitframe_coalesce: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n", - padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3))); + ("%s: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n", + __func__, padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe+1), *(pframe+2), *(pframe+3))); pframe += pattrib->iv_len; @@ -1046,12 +1034,9 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct if ((pattrib->icv_len > 0) && (pattrib->bswenc)) mpdu_len -= pattrib->icv_len; - if (bmcst) { - /* don't do fragment to broadcat/multicast packets */ - mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); - } else { - mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len); - } + mem_sz = min_t(size_t, bmcst ? pattrib->pktlen : mpdu_len, remainder); + skb_copy_bits(pkt, pkt->len - remainder, pframe, mem_sz); + remainder -= mem_sz; pframe += mem_sz; @@ -1062,7 +1047,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct frg_inx++; - if (bmcst || pktfile.pkt_len == 0) { + if (bmcst || remainder == 0) { pattrib->nr_frags = frg_inx; pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) + @@ -1154,7 +1139,7 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) case AUTO_VCS: default: perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); - if (perp == NULL) { + if (!perp) { pxmitpriv->vcs = NONE_VCS; } else { protection = (*(perp + 2)) & BIT(1); @@ -1222,7 +1207,7 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) struct __queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; - if (pxmitbuf == NULL) + if (!pxmitbuf) return _FAIL; spin_lock_irqsave(&pfree_queue->lock, irql); @@ -1268,7 +1253,7 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) unsigned long irql; struct __queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; - if (pxmitbuf == NULL) + if (!pxmitbuf) return _FAIL; if (pxmitbuf->sctx) { @@ -1359,8 +1344,8 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram struct sk_buff *pndis_pkt = NULL; - if (pxmitframe == NULL) { - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe():pxmitframe == NULL!!!!!!!!!!\n")); + if (!pxmitframe) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== %s:pxmitframe == NULL!!!!!!!!!!\n", __func__)); goto exit; } @@ -1376,7 +1361,7 @@ s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitfram list_add_tail(&pxmitframe->list, get_list_head(pfree_xmit_queue)); pxmitpriv->free_xmitframe_cnt++; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe():free_xmitframe_cnt=%d\n", pxmitpriv->free_xmitframe_cnt)); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("%s:free_xmitframe_cnt=%d\n", __func__, pxmitpriv->free_xmitframe_cnt)); spin_unlock_bh(&pfree_xmit_queue->lock); @@ -1415,7 +1400,7 @@ s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitfram { if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) { RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, - ("rtw_xmitframe_enqueue: drop xmit pkt for classifier fail\n")); + ("%s: drop xmit pkt for classifier fail\n", __func__)); /* pxmitframe->pkt = NULL; */ return _FAIL; } @@ -1505,26 +1490,26 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info * case 2: ptxservq = &psta->sta_xmitpriv.bk_q; *(ac) = 3; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : BK\n", __func__)); break; case 4: case 5: ptxservq = &psta->sta_xmitpriv.vi_q; *(ac) = 1; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : VI\n", __func__)); break; case 6: case 7: ptxservq = &psta->sta_xmitpriv.vo_q; *(ac) = 0; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : VO\n", __func__)); break; case 0: case 3: default: ptxservq = &psta->sta_xmitpriv.be_q; *(ac) = 2; - RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n")); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("%s : BE\n", __func__)); break; } @@ -1552,10 +1537,10 @@ s32 rtw_xmit_classifier(struct adapter *padapter, struct xmit_frame *pxmitframe) else psta = rtw_get_stainfo(pstapriv, pattrib->ra); - if (psta == NULL) { + if (!psta) { res = _FAIL; - DBG_88E("rtw_xmit_classifier: psta == NULL\n"); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmit_classifier: psta == NULL\n")); + DBG_88E("%s: psta == NULL\n", __func__); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: psta == NULL\n", __func__)); goto exit; } @@ -1660,8 +1645,8 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) s32 res; pxmitframe = rtw_alloc_xmitframe(pxmitpriv); - if (pxmitframe == NULL) { - RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n")); + if (!pxmitframe) { + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: no more pxmitframe\n", __func__)); DBG_88E("DBG_TX_DROP_FRAME %s no more pxmitframe\n", __func__); return -1; } @@ -1669,7 +1654,7 @@ s32 rtw_xmit(struct adapter *padapter, struct sk_buff **ppkt) res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); if (res == _FAIL) { - RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n")); + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: update attrib fail\n", __func__)); rtw_free_xmitframe(pxmitpriv, pxmitframe); return -1; } @@ -1713,7 +1698,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra else psta = rtw_get_stainfo(pstapriv, pattrib->ra); - if (psta == NULL) + if (!psta) return ret; if (pattrib->triggered == 1) { diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c index 9b7ba9bffb0d..8d242adae4b3 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c @@ -36,7 +36,7 @@ static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num) do { valid = usb_read8(adapt, REG_HMETFR) & BIT(msgbox_num); - if (0 == valid) + if (valid == 0) read_down = true; } while ((!read_down) && (retry_cnts--)); @@ -67,7 +67,8 @@ static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *p if (!adapt->bFWReady) { - DBG_88E("FillH2CCmd_88E(): return H2C cmd because fw is not ready\n"); + DBG_88E("%s(): return H2C cmd because fw is not ready\n", + __func__); return ret; } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c index d04b7fbb71e1..ff227c8b98ca 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_dm.c @@ -182,7 +182,7 @@ void rtw_hal_dm_init(struct adapter *Adapter) /* Compare RSSI for deciding antenna */ void rtw_hal_antdiv_rssi_compared(struct adapter *Adapter, struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src) { - if (0 != Adapter->HalData->AntDivCfg) { + if (Adapter->HalData->AntDivCfg != 0) { /* select optimum_antenna for before linked =>For antenna diversity */ if (dst->Rssi >= src->Rssi) {/* keep org parameter */ src->Rssi = dst->Rssi; diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index 3673f573ac3d..54ede4baa0c9 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -221,13 +221,13 @@ s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) } else { for (i = 0; i < (txpktbuf_bndy - 1); i++) { status = _LLTWrite(padapter, i, i + 1); - if (_SUCCESS != status) + if (status != _SUCCESS) return status; } /* end of list */ status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF); - if (_SUCCESS != status) + if (status != _SUCCESS) return status; /* Make the other pages as ring buffer */ @@ -235,13 +235,13 @@ s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) /* Otherwise used as local loopback buffer. */ for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) { status = _LLTWrite(padapter, i, (i + 1)); - if (_SUCCESS != status) + if (status != _SUCCESS) return status; } /* Let last entry point to the start entry of ring buffer */ status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy); - if (_SUCCESS != status) { + if (status != _SUCCESS) { return status; } } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c index a9912b60eb59..4f0f512f303c 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c @@ -552,7 +552,7 @@ s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitp pbuf = round_up(pbuf_tail, 8); pfirstframe->agg_num++; - if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num) + if (pfirstframe->agg_num == MAX_TX_AGG_PACKET_NUMBER) break; if (pbuf < bulkptr) { diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c index 17967c944946..c3bb183aba38 100644 --- a/drivers/staging/rtl8188eu/hal/usb_halinit.c +++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c @@ -1516,8 +1516,8 @@ void rtw_hal_set_hwreg(struct adapter *Adapter, u8 variable, u8 *val) case HW_VAR_CAM_WRITE: { u32 cmd; - u32 *cam_val = (u32 *)val; + usb_write32(Adapter, WCAMI, cam_val[0]); cmd = CAM_POLLINIG | CAM_WRITE | cam_val[1]; diff --git a/drivers/staging/rtl8188eu/include/rtw_security.h b/drivers/staging/rtl8188eu/include/rtw_security.h index a0c6cf706218..b1883ca852af 100644 --- a/drivers/staging/rtl8188eu/include/rtw_security.h +++ b/drivers/staging/rtl8188eu/include/rtw_security.h @@ -308,6 +308,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe); void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe); u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe); u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe); -void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe); +int rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe); #endif /* __RTL871X_SECURITY_H_ */ diff --git a/drivers/staging/rtl8188eu/include/xmit_osdep.h b/drivers/staging/rtl8188eu/include/xmit_osdep.h index 959ef4b3066c..00ebad88f0d1 100644 --- a/drivers/staging/rtl8188eu/include/xmit_osdep.h +++ b/drivers/staging/rtl8188eu/include/xmit_osdep.h @@ -18,15 +18,6 @@ #include <osdep_service.h> #include <drv_types.h> -struct pkt_file { - struct sk_buff *pkt; - size_t pkt_len; /* the remainder length of the open_file */ - unsigned char *cur_buffer; - u8 *buf_start; - u8 *cur_addr; - size_t buf_len; -}; - #define NR_XMITFRAME 256 struct xmit_priv; @@ -43,10 +34,6 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz); void rtw_os_xmit_resource_free(struct xmit_buf *pxmitbuf); -uint rtw_remainder_len(struct pkt_file *pfile); -void _rtw_open_pktfile(struct sk_buff *pkt, struct pkt_file *pfile); -uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen); - void rtw_os_pkt_complete(struct adapter *padapter, struct sk_buff *pkt); void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe); diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 32c7225a831e..127ecf896fc9 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -333,7 +333,7 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, struct net_device *pmondev; int status = _FAIL; - padapter = (struct adapter *)vzalloc(sizeof(*padapter)); + padapter = vzalloc(sizeof(*padapter)); if (padapter == NULL) goto exit; padapter->dvobj = dvobj; diff --git a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c index 8bf8248e4ac7..8ac9567c954d 100644 --- a/drivers/staging/rtl8188eu/os_dep/xmit_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/xmit_linux.c @@ -22,43 +22,6 @@ #include <xmit_osdep.h> #include <osdep_intf.h> -uint rtw_remainder_len(struct pkt_file *pfile) -{ - return pfile->buf_len - ((size_t)(pfile->cur_addr) - - (size_t)(pfile->buf_start)); -} - -void _rtw_open_pktfile(struct sk_buff *pktptr, struct pkt_file *pfile) -{ - - pfile->pkt = pktptr; - pfile->cur_addr = pktptr->data; - pfile->buf_start = pktptr->data; - pfile->pkt_len = pktptr->len; - pfile->buf_len = pktptr->len; - - pfile->cur_buffer = pfile->buf_start; - -} - -uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen) -{ - uint len = 0; - - - len = rtw_remainder_len(pfile); - len = min(rlen, len); - - if (rmem) - skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len, rmem, len); - - pfile->cur_addr += len; - pfile->pkt_len -= len; - - - return len; -} - int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitbuf, u32 alloc_sz) { int i; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index f802f60281f8..843e874b8a06 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -36,7 +36,6 @@ static int _rtl92e_wx_get_freq(struct net_device *dev, return rtllib_wx_get_freq(priv->rtllib, a, wrqu, b); } - static int _rtl92e_wx_get_mode(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *b) @@ -149,7 +148,6 @@ static int _rtl92e_wx_set_rawtx(struct net_device *dev, mutex_unlock(&priv->wx_mutex); return ret; - } static int _rtl92e_wx_force_reset(struct net_device *dev, @@ -165,7 +163,6 @@ static int _rtl92e_wx_force_reset(struct net_device *dev, priv->force_reset = *extra; mutex_unlock(&priv->wx_mutex); return 0; - } static int _rtl92e_wx_adapter_power_status(struct net_device *dev, @@ -174,7 +171,7 @@ static int _rtl92e_wx_adapter_power_status(struct net_device *dev, { struct r8192_priv *priv = rtllib_priv(dev); struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) - (&(priv->rtllib->PowerSaveControl)); + (&priv->rtllib->PowerSaveControl); struct rtllib_device *ieee = priv->rtllib; mutex_lock(&priv->wx_mutex); @@ -205,7 +202,7 @@ static int _rtl92e_wx_set_lps_awake_interval(struct net_device *dev, { struct r8192_priv *priv = rtllib_priv(dev); struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) - (&(priv->rtllib->PowerSaveControl)); + (&priv->rtllib->PowerSaveControl); mutex_lock(&priv->wx_mutex); @@ -231,7 +228,6 @@ static int _rtl92e_wx_set_force_lps(struct net_device *dev, priv->force_lps = *extra; mutex_unlock(&priv->wx_mutex); return 0; - } static int _rtl92e_wx_set_debug(struct net_device *dev, @@ -247,7 +243,7 @@ static int _rtl92e_wx_set_debug(struct net_device *dev, netdev_info(dev, "=====>%s(), *extra:%x, debugflag:%x\n", __func__, *extra, rt_global_debug_component); if (c > 0) - rt_global_debug_component |= (1<<c); + rt_global_debug_component |= (1 << c); else rt_global_debug_component &= BIT31; return 0; @@ -356,7 +352,7 @@ static int _rtl92e_wx_get_range(struct net_device *dev, range->min_pmp = 0; range->max_pmp = 5000000; range->min_pmt = 0; - range->max_pmt = 65535*1000; + range->max_pmt = 65535 * 1000; range->pmp_flags = IW_POWER_PERIOD; range->pmt_flags = IW_POWER_TIMEOUT; range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; @@ -364,7 +360,7 @@ static int _rtl92e_wx_get_range(struct net_device *dev, range->we_version_source = 18; for (i = 0, val = 0; i < 14; i++) { - if ((priv->rtllib->active_channel_map)[i+1]) { + if ((priv->rtllib->active_channel_map)[i + 1]) { range->freq[val].i = i + 1; range->freq[val].m = rtllib_wlan_frequencies[i] * 100000; @@ -377,8 +373,8 @@ static int _rtl92e_wx_get_range(struct net_device *dev, } range->num_frequency = val; range->num_channels = val; - range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2| - IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP; + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; /* Event capability (kernel + driver) */ @@ -475,12 +471,10 @@ static int _rtl92e_wx_set_scan(struct net_device *dev, return ret; } - static int _rtl92e_wx_get_scan(struct net_device *dev, struct iw_request_info *a, union iwreq_data *wrqu, char *b) { - int ret; struct r8192_priv *priv = rtllib_priv(dev); @@ -490,7 +484,6 @@ static int _rtl92e_wx_get_scan(struct net_device *dev, if (priv->bHwRadioOff) return 0; - mutex_lock(&priv->wx_mutex); ret = rtllib_wx_get_scan(priv->rtllib, a, wrqu, b); @@ -552,7 +545,6 @@ static int _rtl92e_wx_set_nick(struct net_device *dev, memcpy(priv->nick, extra, wrqu->data.length); mutex_unlock(&priv->wx_mutex); return 0; - } static int _rtl92e_wx_get_nick(struct net_device *dev, @@ -596,7 +588,6 @@ static int _rtl92e_wx_get_name(struct net_device *dev, return rtllib_wx_get_name(priv->rtllib, info, wrqu, extra); } - static int _rtl92e_wx_set_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -619,7 +610,6 @@ static int _rtl92e_wx_set_frag(struct net_device *dev, return 0; } - static int _rtl92e_wx_get_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -633,7 +623,6 @@ static int _rtl92e_wx_get_frag(struct net_device *dev, return 0; } - static int _rtl92e_wx_set_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *awrq, char *extra) @@ -651,10 +640,8 @@ static int _rtl92e_wx_set_wap(struct net_device *dev, mutex_unlock(&priv->wx_mutex); return ret; - } - static int _rtl92e_wx_get_wap(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -664,7 +651,6 @@ static int _rtl92e_wx_get_wap(struct net_device *dev, return rtllib_wx_get_wap(priv->rtllib, info, wrqu, extra); } - static int _rtl92e_wx_get_enc(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *key) @@ -707,7 +693,6 @@ static int _rtl92e_wx_set_enc(struct net_device *dev, ret = rtllib_wx_set_encode(priv->rtllib, info, wrqu, key); mutex_unlock(&priv->wx_mutex); - if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA; rtl92e_cam_reset(dev); @@ -716,9 +701,8 @@ static int _rtl92e_wx_set_enc(struct net_device *dev, goto end_hw_sec; } if (wrqu->encoding.length != 0) { - for (i = 0; i < 4; i++) { - hwkey[i] |= key[4*i+0]&mask; + hwkey[i] |= key[4 * i + 0] & mask; if (i == 1 && (4 * i + 1) == wrqu->encoding.length) mask = 0x00; if (i == 3 && (4 * i + 1) == wrqu->encoding.length) @@ -786,8 +770,6 @@ static int _rtl92e_wx_set_scan_type(struct net_device *dev, return 1; } - - #define R8192_MAX_RETRY 255 static int _rtl92e_wx_set_retry(struct net_device *dev, struct iw_request_info *info, @@ -833,7 +815,6 @@ static int _rtl92e_wx_get_retry(struct net_device *dev, { struct r8192_priv *priv = rtllib_priv(dev); - wrqu->retry.disabled = 0; /* can't be disabled */ if ((wrqu->retry.flags & IW_RETRY_TYPE) == @@ -862,12 +843,10 @@ static int _rtl92e_wx_get_sens(struct net_device *dev, return 0; } - static int _rtl92e_wx_set_sens(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct r8192_priv *priv = rtllib_priv(dev); short err = 0; @@ -963,15 +942,12 @@ static int _rtl92e_wx_set_encode_ext(struct net_device *dev, rtl92e_set_swcam(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, 0, key, 0); } - - } end_hw_sec: priv->rtllib->wx_set_enc = 0; mutex_unlock(&priv->wx_mutex); return ret; - } static int _rtl92e_wx_set_auth(struct net_device *dev, @@ -986,7 +962,7 @@ static int _rtl92e_wx_set_auth(struct net_device *dev, return 0; mutex_lock(&priv->wx_mutex); - ret = rtllib_wx_set_auth(priv->rtllib, info, &(data->param), extra); + ret = rtllib_wx_set_auth(priv->rtllib, info, &data->param, extra); mutex_unlock(&priv->wx_mutex); return ret; } @@ -995,7 +971,6 @@ static int _rtl92e_wx_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - int ret = 0; struct r8192_priv *priv = rtllib_priv(dev); @@ -1089,7 +1064,6 @@ static int _rtl92e_wx_set_promisc_mode(struct net_device *dev, return 0; } - static int _rtl92e_wx_get_promisc_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -1109,7 +1083,6 @@ static int _rtl92e_wx_get_promisc_mode(struct net_device *dev, return 0; } - #define IW_IOCTL(x) ((x) - SIOCSIWCOMMIT) static iw_handler r8192_wx_handlers[] = { [IW_IOCTL(SIOCGIWNAME)] = _rtl92e_wx_get_name, @@ -1166,15 +1139,15 @@ static const struct iw_priv_args r8192_private_args[] = { IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset" }, { SIOCIWFIRSTPRIV + 0x6, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "set_power" }, { SIOCIWFIRSTPRIV + 0xa, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "lps_interv" }, { SIOCIWFIRSTPRIV + 0xb, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED|1, IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, IW_PRIV_TYPE_NONE, "lps_force" }, { SIOCIWFIRSTPRIV + 0x16, diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c index eb6d841f7c45..c466a5e7e3bd 100644 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -76,7 +76,7 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, u16 StatusCode, u8 type) { struct sk_buff *skb = NULL; - struct rtllib_hdr_3addr *BAReq = NULL; + struct rtllib_hdr_3addr *BAReq = NULL; u8 *tag = NULL; u16 len = ieee->tx_headroom + 9; diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 30f72d220af1..fa580ce1cf43 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -2644,8 +2644,8 @@ static inline void rtllib_process_probe_response( (network->ssid_len ? 1 : 0))) { update_network(ieee, &ieee->current_network, network); if ((ieee->current_network.mode == IEEE_N_24G || - ieee->current_network.mode == IEEE_G) - && ieee->current_network.berp_info_valid) { + ieee->current_network.mode == IEEE_G) && + ieee->current_network.berp_info_valid) { if (ieee->current_network.erp_value & ERP_UseProtection) ieee->current_network.buseprotection = true; else diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index 03fbff067fa4..74d4d2df3eb3 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -371,8 +371,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, struct lib80211_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), - GFP_KERNEL); + new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; new_crypt->ops = lib80211_get_crypto_ops("R-WEP"); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c index e6648f7723ce..a4b40422e5bd 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_ccmp.c @@ -73,7 +73,7 @@ static void *ieee80211_ccmp_init(int key_idx) priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tfm)) { - printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate crypto API aes\n"); + pr_debug("ieee80211_crypt_ccmp: could not allocate crypto API aes\n"); priv->tfm = NULL; goto fail; } @@ -276,22 +276,22 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) keyidx = pos[3]; if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { - printk(KERN_DEBUG "CCMP: received packet without ExtIV flag from %pM\n", - hdr->addr2); + netdev_dbg(skb->dev, "CCMP: received packet without ExtIV flag from %pM\n", + hdr->addr2); } key->dot11RSNAStatsCCMPFormatErrors++; return -2; } keyidx >>= 6; if (key->key_idx != keyidx) { - printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n", - key->key_idx, keyidx, priv); + netdev_dbg(skb->dev, "CCMP: RX tkey->key_idx=%d frame keyidx=%d priv=%p\n", + key->key_idx, keyidx, priv); return -6; } if (!key->key_set) { if (net_ratelimit()) { - printk(KERN_DEBUG "CCMP: received packet from %pM with keyid=%d that does not have a configured key\n", - hdr->addr2, keyidx); + netdev_dbg(skb->dev, "CCMP: received packet from %pM with keyid=%d that does not have a configured key\n", + hdr->addr2, keyidx); } return -3; } @@ -306,8 +306,8 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { if (net_ratelimit()) { - printk(KERN_DEBUG "CCMP: replay detected: STA=%pM previous PN %pm received PN %pm\n", - hdr->addr2, key->rx_pn, pn); + netdev_dbg(skb->dev, "CCMP: replay detected: STA=%pM previous PN %pm received PN %pm\n", + hdr->addr2, key->rx_pn, pn); } key->dot11RSNAStatsCCMPReplays++; return -4; @@ -341,8 +341,8 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { if (net_ratelimit()) { - printk(KERN_DEBUG "CCMP: decrypt failed: STA=%pM\n", - hdr->addr2); + netdev_dbg(skb->dev, "CCMP: decrypt failed: STA=%pM\n", + hdr->addr2); } key->dot11RSNAStatsCCMPDecryptErrors++; return -5; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index 21b55fd5b717..86c73570e88a 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -195,7 +195,9 @@ static struct sk_buff *ieee80211_DELBA( u16 len = 6 + ieee->tx_headroom; if (net_ratelimit()) - IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:%pM\n", __func__, ReasonCode, dst); + IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, + "========>%s(), ReasonCode(%d) sentd to:%pM\n", + __func__, ReasonCode, dst); memset(&DelbaParamSet, 0, 2); @@ -233,7 +235,8 @@ static struct sk_buff *ieee80211_DELBA( IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); if (net_ratelimit()) - IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "<=====%s()\n", __func__); + IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, + "<=====%s()\n", __func__); return skb; } diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 3c300f7b6a62..d607c59761cf 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -1706,6 +1706,8 @@ static short rtl8192_usb_initendpoints(struct net_device *dev) priv->rx_urb[16] = usb_alloc_urb(0, GFP_KERNEL); priv->oldaddr = kmalloc(16, GFP_KERNEL); + if (!priv->oldaddr) + return -ENOMEM; oldaddr = priv->oldaddr; align = ((long)oldaddr) & 3; if (align) { diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h index ae79047ac6dc..ede99e96984f 100644 --- a/drivers/staging/rtl8712/drv_types.h +++ b/drivers/staging/rtl8712/drv_types.h @@ -161,7 +161,7 @@ struct _adapter { u8 EepromAddressSize; u8 hw_init_completed; struct task_struct *cmdThread; - pid_t evtThread; + pid_t evtThread; struct task_struct *xmitThread; pid_t recvThread; uint (*dvobj_init)(struct _adapter *adapter); diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c index 987270395635..7a4c00e49a88 100644 --- a/drivers/staging/rtl8712/ieee80211.c +++ b/drivers/staging/rtl8712/ieee80211.c @@ -107,7 +107,7 @@ u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen) * index: the information element id index, limit is the limit for search * --------------------------------------------------------------------------- */ -u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit) +u8 *r8712_get_ie(u8 *pbuf, sint index, uint *len, sint limit) { sint tmp, i; u8 *p; @@ -166,7 +166,8 @@ static uint r8712_get_rateset_len(u8 *rateset) int r8712_generate_ie(struct registry_priv *pregistrypriv) { - int sz = 0, rate_len; + int rate_len; + uint sz = 0; struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network; u8 *ie = pdev_network->IEs; u16 beaconPeriod = (u16)pdev_network->Configuration.BeaconPeriod; @@ -211,9 +212,9 @@ int r8712_generate_ie(struct registry_priv *pregistrypriv) return sz; } -unsigned char *r8712_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) +unsigned char *r8712_get_wpa_ie(unsigned char *pie, uint *wpa_ie_len, int limit) { - int len; + u32 len; u16 val16; unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; u8 *pbuf = pie; @@ -245,7 +246,7 @@ check_next_ie: return NULL; } -unsigned char *r8712_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) +unsigned char *r8712_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len, int limit) { return r8712_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); } diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h index 68fd65e80906..d605dfd02200 100644 --- a/drivers/staging/rtl8712/ieee80211.h +++ b/drivers/staging/rtl8712/ieee80211.h @@ -738,9 +738,9 @@ static inline int ieee80211_get_hdrlen(u16 fc) struct registry_priv; u8 *r8712_set_ie(u8 *pbuf, sint index, uint len, u8 *source, uint *frlen); -u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit); -unsigned char *r8712_get_wpa_ie(unsigned char *pie, int *rsn_ie_len, int limit); -unsigned char *r8712_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, +u8 *r8712_get_ie(u8 *pbuf, sint index, uint *len, sint limit); +unsigned char *r8712_get_wpa_ie(unsigned char *pie, uint *rsn_ie_len, int limit); +unsigned char *r8712_get_wpa2_ie(unsigned char *pie, uint *rsn_ie_len, int limit); int r8712_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher); diff --git a/drivers/staging/rtl8712/mlme_linux.c b/drivers/staging/rtl8712/mlme_linux.c index 3c7c4a4faeb2..baaa52f04560 100644 --- a/drivers/staging/rtl8712/mlme_linux.c +++ b/drivers/staging/rtl8712/mlme_linux.c @@ -36,7 +36,7 @@ static void sitesurvey_ctrl_handler(struct timer_list *t) { struct _adapter *adapter = from_timer(adapter, t, - mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer); + mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer); _r8712_sitesurvey_ctrl_handler(adapter); mod_timer(&adapter->mlmepriv.sitesurveyctrl.sitesurvey_ctrl_timer, diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c index e7df5d7986fc..ff4e451c10f9 100644 --- a/drivers/staging/rtl8712/os_intfs.c +++ b/drivers/staging/rtl8712/os_intfs.c @@ -230,7 +230,7 @@ struct net_device *r8712_init_netdev(void) static u32 start_drv_threads(struct _adapter *padapter) { padapter->cmdThread = kthread_run(r8712_cmd_thread, padapter, "%s", - padapter->pnetdev->name); + padapter->pnetdev->name); if (IS_ERR(padapter->cmdThread)) return _FAIL; return _SUCCESS; @@ -347,7 +347,6 @@ u8 r8712_free_drv_sw(struct _adapter *padapter) return _SUCCESS; } - static void enable_video_mode(struct _adapter *padapter, int cbw40_value) { /* bit 8: diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c index 986a55bb9877..8cf4286f6318 100644 --- a/drivers/staging/rtl8712/recv_linux.c +++ b/drivers/staging/rtl8712/recv_linux.c @@ -111,8 +111,8 @@ void r8712_recv_indicatepkt(struct _adapter *padapter, _pkt *skb; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - precvpriv = &(padapter->recvpriv); - pfree_recv_queue = &(precvpriv->free_recv_queue); + precvpriv = &padapter->recvpriv; + pfree_recv_queue = &precvpriv->free_recv_queue; skb = precv_frame->u.hdr.pkt; if (!skb) goto _recv_indicatepkt_drop; diff --git a/drivers/staging/rtl8712/rtl8712_bitdef.h b/drivers/staging/rtl8712/rtl8712_bitdef.h index bff57a8eef3c..dee35fe2587a 100644 --- a/drivers/staging/rtl8712/rtl8712_bitdef.h +++ b/drivers/staging/rtl8712/rtl8712_bitdef.h @@ -18,7 +18,6 @@ * ******************************************************************************/ - #ifndef __RTL8712_BITDEF_H__ #define __RTL8712_BITDEF_H__ diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c index 9c8e0c50a804..b1dfe9f46619 100644 --- a/drivers/staging/rtl8712/rtl8712_cmd.c +++ b/drivers/staging/rtl8712/rtl8712_cmd.c @@ -320,7 +320,7 @@ int r8712_cmd_thread(void *context) struct tx_desc *pdesc; void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd); struct _adapter *padapter = context; - struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; struct completion *cmd_queue_comp = &pcmdpriv->cmd_queue_comp; struct mutex *pwctrl_lock = &padapter->pwrctrlpriv.mutex_lock; @@ -334,7 +334,7 @@ int r8712_cmd_thread(void *context) if (r8712_register_cmd_alive(padapter) != _SUCCESS) continue; _next: - pcmd = r8712_dequeue_cmd(&(pcmdpriv->cmd_queue)); + pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue); if (!(pcmd)) { r8712_unregister_cmd_alive(padapter); continue; @@ -419,7 +419,7 @@ _next: } /* free all cmd_obj resources */ do { - pcmd = r8712_dequeue_cmd(&(pcmdpriv->cmd_queue)); + pcmd = r8712_dequeue_cmd(&pcmdpriv->cmd_queue); if (!pcmd) break; r8712_free_cmd_obj(pcmd); @@ -433,7 +433,7 @@ void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf) u8 evt_code, evt_seq; u16 evt_sz; void (*event_callback)(struct _adapter *dev, u8 *pbuf); - struct evt_priv *pevt_priv = &(padapter->evtpriv); + struct evt_priv *pevt_priv = &padapter->evtpriv; if (!peventbuf) goto _abort_event_; diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h index 67e9e910aef9..9181bb6b04c3 100644 --- a/drivers/staging/rtl8712/rtl8712_cmd.h +++ b/drivers/staging/rtl8712/rtl8712_cmd.h @@ -145,8 +145,8 @@ enum rtl8712_h2c_cmd { #define _SetBBReg_CMD_ _Write_BBREG_CMD_ #define _GetRFReg_CMD_ _Read_RFREG_CMD_ #define _SetRFReg_CMD_ _Write_RFREG_CMD_ -#define _DRV_INT_CMD_ (MAX_H2CCMD+1) -#define _SetRFIntFs_CMD_ (MAX_H2CCMD+2) +#define _DRV_INT_CMD_ (MAX_H2CCMD + 1) +#define _SetRFIntFs_CMD_ (MAX_H2CCMD + 2) #ifdef _RTL8712_CMD_C_ static struct _cmd_callback cmd_callback[] = { diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h index b7dda903001f..4b8985d50098 100644 --- a/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h +++ b/drivers/staging/rtl8712/rtl8712_cmdctrl_bitdef.h @@ -63,7 +63,7 @@ #define _IMEM_CHK_RPT BIT(1) #define _IMEM_CODE_DONE BIT(0) -#define _TXDMA_INIT_VALUE (_IMEM_CHK_RPT|_EMEM_CHK_RPT) +#define _TXDMA_INIT_VALUE (_IMEM_CHK_RPT | _EMEM_CHK_RPT) /*RCR*/ #define _ENMBID BIT(27) diff --git a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h index 9374f1c48853..8df42a70399f 100644 --- a/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h +++ b/drivers/staging/rtl8712/rtl8712_cmdctrl_regdef.h @@ -20,7 +20,6 @@ #ifndef __RTL8712_CMDCTRL_REGDEF_H__ #define __RTL8712_CMDCTRL_REGDEF_H__ - #define CR (RTL8712_CMDCTRL_ + 0x0000) #define TXPAUSE (RTL8712_CMDCTRL_ + 0x0002) #define TCR (RTL8712_CMDCTRL_ + 0x0004) @@ -29,6 +28,5 @@ #define SYSF_CFG (RTL8712_CMDCTRL_ + 0x000D) #define MBIDCTRL (RTL8712_CMDCTRL_ + 0x000E) - #endif /* __RTL8712_CMDCTRL_REGDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h index 8bd483795ca4..4b3436795cb1 100644 --- a/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h +++ b/drivers/staging/rtl8712/rtl8712_debugctrl_bitdef.h @@ -51,5 +51,4 @@ /*FDLOCKFLAG1*/ #define _LOCKFLAG1_MSK 0x03 - #endif /* __RTL8712_DEBUGCTRL_BITDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h index 43630bb068f5..d7c964d436a1 100644 --- a/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h +++ b/drivers/staging/rtl8712/rtl8712_debugctrl_regdef.h @@ -41,7 +41,5 @@ #define TRXPKTBUF_DBG_CTRL (RTL8712_DEBUGCTRL_ + 0x38) #define DPLL_MON (RTL8712_DEBUGCTRL_ + 0x3A) - - #endif /* __RTL8712_DEBUGCTRL_REGDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h index c564dc862d9d..bd8240476d71 100644 --- a/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h +++ b/drivers/staging/rtl8712/rtl8712_fifoctrl_bitdef.h @@ -140,6 +140,5 @@ /*TXFF_PG_NUM*/ #define _TXFF_PG_NUM_MSK 0x0FFF - #endif /* __RTL8712_FIFOCTRL_BITDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h b/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h index 29b89c45c70c..6d527380fd29 100644 --- a/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h +++ b/drivers/staging/rtl8712/rtl8712_fifoctrl_regdef.h @@ -71,6 +71,4 @@ #define TXQ_PGADD (RTL8712_FIFOCTRL_ + 0xB3) #define TXFF_PG_NUM (RTL8712_FIFOCTRL_ + 0xB4) - - #endif /* __RTL8712_FIFOCTRL_REGDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h index 44c906097530..66c35c990983 100644 --- a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h +++ b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h @@ -70,7 +70,7 @@ #define GPIOSEL_PHYDBG 1 /* PHYDBG*/ #define GPIOSEL_BT 2 /* BT_coex*/ #define GPIOSEL_WLANDBG 3 /* WLANDBG*/ -#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1))) +#define GPIOSEL_GPIO_MASK (~(BIT(0) | BIT(1))) /* HW Radio OFF switch (GPIO BIT) */ #define HAL_8192S_HW_GPIO_OFF_BIT BIT(3) #define HAL_8192S_HW_GPIO_OFF_MASK 0xF7 diff --git a/drivers/staging/rtl8712/rtl8712_gp_regdef.h b/drivers/staging/rtl8712/rtl8712_gp_regdef.h index 8fc68f6a2c79..a0379360d0a3 100644 --- a/drivers/staging/rtl8712/rtl8712_gp_regdef.h +++ b/drivers/staging/rtl8712/rtl8712_gp_regdef.h @@ -37,6 +37,5 @@ #define PHY_REG_RPT (RTL8712_GP_ + 0x13) #define PHY_REG_DATA (RTL8712_GP_ + 0x14) - #endif /*__RTL8712_GP_REGDEF_H__ */ diff --git a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h b/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h index 49598c314f09..2a561d2862e0 100644 --- a/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h +++ b/drivers/staging/rtl8712/rtl8712_interrupt_bitdef.h @@ -53,6 +53,5 @@ #define _VODOK BIT(1) #define _RXOK BIT(0) - #endif /*__RTL8712_INTERRUPT_BITDEF_H__*/ diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c index 455fba721135..e9077347837e 100644 --- a/drivers/staging/rtl8712/rtl8712_led.c +++ b/drivers/staging/rtl8712/rtl8712_led.c @@ -181,11 +181,11 @@ static void SwLedOff(struct _adapter *padapter, struct LED_871x *pLed) */ void r8712_InitSwLeds(struct _adapter *padapter) { - struct led_priv *pledpriv = &(padapter->ledpriv); + struct led_priv *pledpriv = &padapter->ledpriv; pledpriv->LedControlHandler = LedControl871x; - InitLed871x(padapter, &(pledpriv->SwLed0), LED_PIN_LED0); - InitLed871x(padapter, &(pledpriv->SwLed1), LED_PIN_LED1); + InitLed871x(padapter, &pledpriv->SwLed0, LED_PIN_LED0); + InitLed871x(padapter, &pledpriv->SwLed1, LED_PIN_LED1); } /* Description: @@ -193,10 +193,10 @@ void r8712_InitSwLeds(struct _adapter *padapter) */ void r8712_DeInitSwLeds(struct _adapter *padapter) { - struct led_priv *ledpriv = &(padapter->ledpriv); + struct led_priv *ledpriv = &padapter->ledpriv; - DeInitLed871x(&(ledpriv->SwLed0)); - DeInitLed871x(&(ledpriv->SwLed1)); + DeInitLed871x(&ledpriv->SwLed0); + DeInitLed871x(&ledpriv->SwLed1); } /* Description: @@ -206,7 +206,7 @@ void r8712_DeInitSwLeds(struct _adapter *padapter) static void SwLedBlink(struct LED_871x *pLed) { struct _adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; u8 bStopBlinking = false; /* Change LED according to BlinkingLedState specified. */ @@ -281,14 +281,14 @@ static void SwLedBlink(struct LED_871x *pLed) static void SwLedBlink1(struct LED_871x *pLed) { struct _adapter *padapter = pLed->padapter; - struct led_priv *ledpriv = &(padapter->ledpriv); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct eeprom_priv *peeprompriv = &(padapter->eeprompriv); - struct LED_871x *pLed1 = &(ledpriv->SwLed1); + struct led_priv *ledpriv = &padapter->ledpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct eeprom_priv *peeprompriv = &padapter->eeprompriv; + struct LED_871x *pLed1 = &ledpriv->SwLed1; u8 bStopBlinking = false; if (peeprompriv->CustomerID == RT_CID_819x_CAMEO) - pLed = &(ledpriv->SwLed1); + pLed = &ledpriv->SwLed1; /* Change LED according to BlinkingLedState specified. */ if (pLed->BlinkingLedState == LED_STATE_ON) SwLedOn(padapter, pLed); @@ -499,7 +499,7 @@ static void SwLedBlink2(struct LED_871x *pLed) static void SwLedBlink3(struct LED_871x *pLed) { struct _adapter *padapter = pLed->padapter; - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; u8 bStopBlinking = false; /* Change LED according to BlinkingLedState specified. */ @@ -593,8 +593,8 @@ static void SwLedBlink3(struct LED_871x *pLed) static void SwLedBlink4(struct LED_871x *pLed) { struct _adapter *padapter = pLed->padapter; - struct led_priv *ledpriv = &(padapter->ledpriv); - struct LED_871x *pLed1 = &(ledpriv->SwLed1); + struct led_priv *ledpriv = &padapter->ledpriv; + struct LED_871x *pLed1 = &ledpriv->SwLed1; u8 bStopBlinking = false; /* Change LED according to BlinkingLedState specified. */ @@ -844,7 +844,7 @@ static void BlinkWorkItemCallback(struct work_struct *work) { struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem); - struct led_priv *ledpriv = &(pLed->padapter->ledpriv); + struct led_priv *ledpriv = &pLed->padapter->ledpriv; switch (ledpriv->LedStrategy) { case SW_LED_MODE0: @@ -886,13 +886,13 @@ static void BlinkWorkItemCallback(struct work_struct *work) static void SwLedControlMode1(struct _adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &(padapter->ledpriv); - struct LED_871x *pLed = &(ledpriv->SwLed0); - struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct sitesurvey_ctrl *psitesurveyctrl = &(pmlmepriv->sitesurveyctrl); + struct led_priv *ledpriv = &padapter->ledpriv; + struct LED_871x *pLed = &ledpriv->SwLed0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sitesurvey_ctrl *psitesurveyctrl = &pmlmepriv->sitesurveyctrl; if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO) - pLed = &(ledpriv->SwLed1); + pLed = &ledpriv->SwLed1; switch (LedAction) { case LED_CTL_START_TO_LINK: case LED_CTL_NO_LINK: @@ -1106,9 +1106,9 @@ static void SwLedControlMode1(struct _adapter *padapter, static void SwLedControlMode2(struct _adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &(padapter->ledpriv); + struct led_priv *ledpriv = &padapter->ledpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); + struct LED_871x *pLed = &ledpriv->SwLed0; switch (LedAction) { case LED_CTL_SITE_SURVEY: @@ -1239,9 +1239,9 @@ static void SwLedControlMode2(struct _adapter *padapter, static void SwLedControlMode3(struct _adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &(padapter->ledpriv); + struct led_priv *ledpriv = &padapter->ledpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); + struct LED_871x *pLed = &ledpriv->SwLed0; switch (LedAction) { case LED_CTL_SITE_SURVEY: @@ -1383,10 +1383,10 @@ static void SwLedControlMode3(struct _adapter *padapter, static void SwLedControlMode4(struct _adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &(padapter->ledpriv); + struct led_priv *ledpriv = &padapter->ledpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); - struct LED_871x *pLed1 = &(ledpriv->SwLed1); + struct LED_871x *pLed = &ledpriv->SwLed0; + struct LED_871x *pLed1 = &ledpriv->SwLed1; switch (LedAction) { case LED_CTL_START_TO_LINK: @@ -1650,12 +1650,12 @@ static void SwLedControlMode4(struct _adapter *padapter, static void SwLedControlMode5(struct _adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &(padapter->ledpriv); + struct led_priv *ledpriv = &padapter->ledpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); + struct LED_871x *pLed = &ledpriv->SwLed0; if (padapter->eeprompriv.CustomerID == RT_CID_819x_CAMEO) - pLed = &(ledpriv->SwLed1); + pLed = &ledpriv->SwLed1; switch (LedAction) { case LED_CTL_POWER_ON: @@ -1723,9 +1723,9 @@ static void SwLedControlMode5(struct _adapter *padapter, static void SwLedControlMode6(struct _adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &(padapter->ledpriv); + struct led_priv *ledpriv = &padapter->ledpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct LED_871x *pLed = &(ledpriv->SwLed0); + struct LED_871x *pLed = &ledpriv->SwLed0; switch (LedAction) { case LED_CTL_POWER_ON: @@ -1737,7 +1737,7 @@ static void SwLedControlMode6(struct _adapter *padapter, pLed->CurrLedState = LED_STATE_ON; pLed->BlinkingLedState = LED_STATE_ON; pLed->bLedBlinkInProgress = false; - mod_timer(&(pLed->BlinkTimer), jiffies + msecs_to_jiffies(0)); + mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(0)); break; case LED_CTL_TX: case LED_CTL_RX: @@ -1807,7 +1807,7 @@ static void SwLedControlMode6(struct _adapter *padapter, */ void LedControl871x(struct _adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &(padapter->ledpriv); + struct led_priv *ledpriv = &padapter->ledpriv; if (!ledpriv->bRegUseLed) return; diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 78245080e328..ac547ddd72d1 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -1725,7 +1725,8 @@ unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) { u8 *p, max_ampdu_sz; - int i, len; + int i; + uint len; struct sta_info *bmc_sta, *psta; struct ieee80211_ht_cap *pht_capie; struct recv_reorder_ctrl *preorder_ctrl; diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c index eda2aee02ff8..a8ae14ce6613 100644 --- a/drivers/staging/rtl8712/rtl871x_xmit.c +++ b/drivers/staging/rtl8712/rtl871x_xmit.c @@ -717,7 +717,7 @@ void r8712_update_protection(struct _adapter *padapter, u8 *ie, uint ie_len) { uint protection; u8 *perp; - sint erp_len; + uint erp_len; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct registry_priv *pregistrypriv = &padapter->registrypriv; diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index af0a9e0a00df..9e132f943687 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -1742,7 +1742,7 @@ exit: return res; } -u32 g_wait_hiq_empty = 0; +u32 g_wait_hiq_empty; static void rtw_chk_hi_queue_hdl(struct adapter *padapter) { diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c index 9167900b5f7d..74750dbce379 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c @@ -1380,8 +1380,8 @@ int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *act fc = le16_to_cpu(((struct ieee80211_hdr_3addr *)frame)->frame_control); - if ((fc & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) - != (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION) + if ((fc & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) + != (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION) ) { return false; } diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index fe739eb2cf7d..c13e514a655a 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -14,6 +14,7 @@ ******************************************************************************/ #define _RTW_MLME_C_ +#include <linux/etherdevice.h> #include <drv_types.h> #include <rtw_debug.h> #include <linux/jiffies.h> @@ -2109,7 +2110,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) mlme->roam_network = candidate; if (!memcmp(candidate->network.MacAddress, mlme->roam_tgt_addr, ETH_ALEN)) - memset(mlme->roam_tgt_addr, 0, ETH_ALEN); + eth_zero_addr(mlme->roam_tgt_addr); } ret = _SUCCESS; diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 7d7756e40bcb..589fab24bb25 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1219,7 +1219,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) } - if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { + if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) { DBG_871X("handle_assoc(reassoc =%d) - too short payload (len =%lu)" "\n", reassoc, (unsigned long)pkt_len); return _FAIL; @@ -1236,8 +1236,8 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) /* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN+2)); */ listen_interval = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN+2); - left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); - pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); + left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset); + pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset); DBG_871X("%s\n", __func__); @@ -4263,7 +4263,7 @@ unsigned int send_beacon(struct adapter *padapter) issue_beacon(padapter, 100); issue++; do { - yield(); + cond_resched(); rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); poll++; } while ((poll%10) != 0 && false == bxmitok && !padapter->bSurpriseRemoved && !padapter->bDriverStopped); diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index 4a6af72013fa..85f7769ecc2d 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -701,7 +701,7 @@ void LPS_Leave_check( bReady = false; start_time = jiffies; - yield(); + cond_resched(); while (1) { down(&pwrpriv->lock); diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 9c7c3be0553a..86f995b8a88b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1785,7 +1785,7 @@ static union recv_frame *recvframe_defrag(struct adapter *adapter, pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; plist = get_next(plist); - }; + } /* free the defrag_q queue and return the prframe */ rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index dec887a5b338..1cef1d77977c 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -1680,18 +1680,18 @@ void rtw_store_phy_info(struct adapter *padapter, union recv_frame *prframe) struct hal_com_data *pHalData = GET_HAL_DATA(padapter); struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; - PODM_PHY_INFO_T pPhyInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info); + struct odm_phy_info *pPhyInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info); struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; psample_pkt_rssi->data_rate = pattrib->data_rate; isCCKrate = pattrib->data_rate <= DESC_RATE11M; - psample_pkt_rssi->pwdball = pPhyInfo->RxPWDBAll; - psample_pkt_rssi->pwr_all = pPhyInfo->RecvSignalPower; + psample_pkt_rssi->pwdball = pPhyInfo->rx_pwd_ba11; + psample_pkt_rssi->pwr_all = pPhyInfo->recv_signal_power; for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { - psample_pkt_rssi->mimo_singal_strength[rf_path] = pPhyInfo->RxMIMOSignalStrength[rf_path]; - psample_pkt_rssi->mimo_singal_quality[rf_path] = pPhyInfo->RxMIMOSignalQuality[rf_path]; + psample_pkt_rssi->mimo_singal_strength[rf_path] = pPhyInfo->rx_mimo_signal_strength[rf_path]; + psample_pkt_rssi->mimo_singal_quality[rf_path] = pPhyInfo->rx_mimo_signal_quality[rf_path]; if (!isCCKrate) { psample_pkt_rssi->ofdm_pwr[rf_path] = pPhyInfo->RxPwr[rf_path]; psample_pkt_rssi->ofdm_snr[rf_path] = pPhyInfo->RxSNR[rf_path]; diff --git a/drivers/staging/rtl8723bs/hal/odm.h b/drivers/staging/rtl8723bs/hal/odm.h index 87a76bafecb3..1037b88e8f08 100644 --- a/drivers/staging/rtl8723bs/hal/odm.h +++ b/drivers/staging/rtl8723bs/hal/odm.h @@ -17,7 +17,6 @@ #ifndef __HALDMOUTSRC_H__ #define __HALDMOUTSRC_H__ - #include "odm_EdcaTurboCheck.h" #include "odm_DIG.h" #include "odm_PathDiv.h" @@ -32,7 +31,6 @@ #define TRAFFIC_HIGH 1 #define NONE 0 - /* 3 Tx Power Tracking */ /* 3 ============================================================ */ #define DPK_DELTA_MAPPING_NUM 13 @@ -81,7 +79,6 @@ #define AUX_ANT 2 /* AntB or Ant Aux */ #define MAX_ANT 3 /* 3 for AP using */ - /* Antenna Diversity Type */ #define SW_ANTDIV 0 #define HW_ANTDIV 1 @@ -200,7 +197,6 @@ typedef struct _ODM_RATE_ADAPTIVE { } ODM_RATE_ADAPTIVE, *PODM_RATE_ADAPTIVE; - #define IQK_MAC_REG_NUM 4 #define IQK_ADDA_REG_NUM 16 #define IQK_BB_REG_NUM_MAX 10 @@ -229,49 +225,49 @@ typedef struct _ODM_RATE_ADAPTIVE { #define MAX_PATH_NUM_8814A 4 #define MAX_PATH_NUM_8822B 2 - #define IQK_THRESHOLD 8 #define DPK_THRESHOLD 4 -typedef struct _ODM_Phy_Status_Info_ { - /* */ - /* Be care, if you want to add any element please insert between */ - /* RxPWDBAll & SignalStrength. */ - /* */ - u8 RxPWDBAll; - - u8 SignalQuality; /* in 0-100 index. */ - s8 RxMIMOSignalQuality[4]; /* per-path's EVM */ - u8 RxMIMOEVMdbm[4]; /* per-path's EVM dbm */ +struct odm_phy_info { + /* + * Be care, if you want to add any element, please insert it between + * rx_pwd_ball and signal_strength. + */ + u8 rx_pwd_ba11; - u8 RxMIMOSignalStrength[4];/* in 0~100 index */ + u8 signal_quality; /* in 0-100 index. */ + s8 rx_mimo_signal_quality[4]; /* per-path's EVM */ + u8 rx_mimo_evm_dbm[4]; /* per-path's EVM dbm */ - u16 Cfo_short[4]; /* per-path's Cfo_short */ - u16 Cfo_tail[4]; /* per-path's Cfo_tail */ + u8 rx_mimo_signal_strength[4]; /* in 0~100 index */ - s8 RxPower; /* in dBm Translate from PWdB */ - s8 RecvSignalPower; /* Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */ - u8 BTRxRSSIPercentage; - u8 SignalStrength; /* in 0-100 index. */ + u16 cfo_short[4]; /* per-path's Cfo_short */ + u16 cfo_tail[4]; /* per-path's Cfo_tail */ - s8 RxPwr[4]; /* per-path's pwdb */ + s8 rx_power; /* in dBm Translate from PWdB */ - u8 RxSNR[4]; /* per-path's SNR */ - u8 BandWidth; - u8 btCoexPwrAdjust; -} ODM_PHY_INFO_T, *PODM_PHY_INFO_T; + /* + * Real power in dBm for this packet, no beautification and + * aggregation. Keep this raw info to be used for the other procedures. + */ + s8 recv_signal_power; + u8 bt_rx_rssi_percentage; + u8 signal_strength; /* in 0-100 index. */ + s8 rx_pwr[4]; /* per-path's pwdb */ -typedef struct _ODM_Per_Pkt_Info_ { - /* u8 Rate; */ - u8 DataRate; - u8 StationID; - bool bPacketMatchBSSID; - bool bPacketToSelf; - bool bPacketBeacon; - bool bToSelf; -} ODM_PACKET_INFO_T, *PODM_PACKET_INFO_T; + u8 rx_snr[4]; /* per-path's SNR */ + u8 band_width; + u8 bt_coex_pwr_adjust; +}; +struct odm_packet_info { + u8 data_rate; + u8 station_id; + bool bssid_match; + bool to_self; + bool is_beacon; +}; typedef struct _ODM_Phy_Dbg_Info_ { /* ODM Write, debug info */ @@ -285,12 +281,10 @@ typedef struct _ODM_Phy_Dbg_Info_ { } ODM_PHY_DBG_INFO_T; - typedef struct _ODM_Mac_Status_Info_ { u8 test; } ODM_MAC_INFO; - typedef enum tag_Dynamic_ODM_Support_Ability_Type { /* BB Team */ ODM_DIG = 0x00000001, @@ -369,7 +363,6 @@ typedef enum _ODM_Common_Info_Definition { ODM_CMNINFO_SMART_CONCURRENT, /* HOOK BEFORE REG INIT----------- */ - /* Dynamic value: */ /* POINTER REFERENCE----------- */ ODM_CMNINFO_MAC_PHY_MODE, /* ODM_MAC_PHY_MODE_E */ @@ -427,8 +420,6 @@ typedef enum _ODM_Common_Info_Definition { ODM_CMNINFO_MAC_STATUS, ODM_CMNINFO_MAX, - - } ODM_CMNINFO_E; /* 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY */ @@ -509,7 +500,6 @@ typedef enum tag_ODM_RF_Path_Bit_Definition { ODM_RF_RX_D = BIT7, } ODM_RF_PATH_E; - typedef enum tag_ODM_RF_Type_Definition { ODM_1T1R = 0, ODM_1T2R = 1, @@ -521,7 +511,6 @@ typedef enum tag_ODM_RF_Type_Definition { ODM_4T4R = 7, } ODM_RF_TYPE_E; - /* */ /* ODM Dynamic common info value definition */ /* */ @@ -538,7 +527,6 @@ typedef enum tag_ODM_MAC_PHY_Mode_Definition { ODM_DMDP = 2, } ODM_MAC_PHY_MODE_E; - typedef enum tag_BT_Coexist_Definition { ODM_BT_BUSY = 1, ODM_BT_ON = 2, @@ -607,7 +595,6 @@ typedef enum tag_Bandwidth_Definition { ODM_BW10M = 4, } ODM_BW_E; - /* ODM_CMNINFO_BOARD_TYPE */ /* For non-AC-series IC , ODM_BOARD_5G_EXT_PA and ODM_BOARD_5G_EXT_LNA are ignored */ /* For AC-series IC, external PA & LNA can be indivisuallly added on 2.4G and/or 5G */ @@ -661,7 +648,6 @@ typedef enum tag_CCA_Path { ODM_CCA_1R_B = 2, } ODM_CCA_PATH_E; - typedef struct _ODM_RA_Info_ { u8 RateID; u32 RateMask; @@ -700,7 +686,6 @@ typedef struct _IQK_MATRIX_REGS_SETTING { bool bBWIqkResultSaved[3]; } IQK_MATRIX_REGS_SETTING, *PIQK_MATRIX_REGS_SETTING; - /* Remove PATHDIV_PARA struct to odm_PathDiv.h */ typedef struct ODM_RF_Calibration_Structure { @@ -736,7 +721,6 @@ typedef struct ODM_RF_Calibration_Structure { u8 bRfPiEnable; u32 TXPowerTrackingCallbackCnt; /* cosa add for debug */ - /* Tx power Tracking ------------------------- */ u8 bCCKinCH14; u8 CCK_index; @@ -791,7 +775,6 @@ typedef struct ODM_RF_Calibration_Structure { u32 TxIQC_8723B[2][3][2]; /* { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}} */ u32 RxIQC_8723B[2][2][2]; /* { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}} */ - /* for APK */ u32 APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */ u8 bAPKdone; @@ -839,7 +822,6 @@ typedef struct _FAST_ANTENNA_TRAINNING_ { u32 OFDM_counter_main; u32 OFDM_counter_aux; - u32 CCK_CtrlFrame_Cnt_main; u32 CCK_CtrlFrame_Cnt_aux; u32 OFDM_CtrlFrame_Cnt_main; @@ -875,13 +857,11 @@ typedef struct _ODM_PATH_DIVERSITY_ { u32 PathB_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; } PATHDIV_T, *pPATHDIV_T; - typedef enum _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE{ PHY_REG_PG_RELATIVE_VALUE = 0, PHY_REG_PG_EXACT_VALUE = 1 } PHY_REG_PG_TYPE; - /* */ /* Antenna detection information from single tone mechanism, added by Roger, 2012.11.27. */ /* */ @@ -933,7 +913,6 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { /* bool bSlaveOfDMSP; */ /* REMOVED COMMON INFO---------- */ - /* 1 COMMON INFORMATION */ /* */ @@ -1105,7 +1084,6 @@ typedef struct DM_Out_Source_Dynamic_Mechanism_Structure { u8 Adaptivity_IGI_upper; u8 NHM_cnt_0; - ODM_NOISE_MONITOR noise_level;/* ODM_MAX_CHANNEL_NUM]; */ /* */ /* 2 Define STA info. */ @@ -1367,7 +1345,6 @@ typedef enum tag_SW_Antenna_Switch_Definition { Antenna_MAX = 3, } DM_SWAS_E; - /* Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. */ #define MAX_ANTENNA_DETECTION_CNT 10 @@ -1400,7 +1377,6 @@ extern u32 TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE]; void ODM_SetAntenna(PDM_ODM_T pDM_Odm, u8 Antenna); - /* Remove BB power saving by Yuchen */ #define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck @@ -1417,7 +1393,7 @@ bool ODM_RAStateCheck( void ODM_SwAntDivChkPerPktRssi( PDM_ODM_T pDM_Odm, u8 StationID, - PODM_PHY_INFO_T pPhyInfo + struct odm_phy_info *pPhyInfo ); u32 ODM_Get_Rate_Bitmap( diff --git a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c index 71853e6f7106..178aaab3f76c 100644 --- a/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c +++ b/drivers/staging/rtl8723bs/hal/odm_CfoTracking.c @@ -316,14 +316,14 @@ void ODM_CfoTracking(void *pDM_VOID) void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail) { PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; - PODM_PACKET_INFO_T pPktinfo = (PODM_PACKET_INFO_T)pPktinfo_VOID; + struct odm_packet_info *pPktinfo = (struct odm_packet_info *)pPktinfo_VOID; PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack; u8 i; if (!(pDM_Odm->SupportAbility & ODM_BB_CFO_TRACKING)) return; - if (pPktinfo->StationID != 0) { + if (pPktinfo->station_id != 0) { /* 3 Update CFO report for path-A & path-B */ /* Only paht-A and path-B have CFO tail and short CFO */ for (i = ODM_RF_PATH_A; i <= ODM_RF_PATH_B; i++) diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c index 8dd6da8a4e26..9e161f080c57 100644 --- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.c +++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.c @@ -91,9 +91,9 @@ static u8 odm_EVMdbToPercentage(s8 Value) static void odm_RxPhyStatus92CSeries_Parsing( PDM_ODM_T pDM_Odm, - PODM_PHY_INFO_T pPhyInfo, + struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, - PODM_PACKET_INFO_T pPktinfo + struct odm_packet_info *pPktinfo ) { u8 i, Max_spatial_stream; @@ -106,9 +106,9 @@ static void odm_RxPhyStatus92CSeries_Parsing( u8 LNA_idx, VGA_idx; PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pPhyStatus; - isCCKrate = pPktinfo->DataRate <= DESC_RATE11M; - pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1; - pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; + isCCKrate = pPktinfo->data_rate <= DESC_RATE11M; + pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_A] = -1; + pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1; if (isCCKrate) { @@ -137,9 +137,9 @@ static void odm_RxPhyStatus92CSeries_Parsing( if (PWDB_ALL > 100) PWDB_ALL = 100; - pPhyInfo->RxPWDBAll = PWDB_ALL; - pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; - pPhyInfo->RecvSignalPower = rx_pwr_all; + pPhyInfo->rx_pwd_ba11 = PWDB_ALL; + pPhyInfo->bt_rx_rssi_percentage = PWDB_ALL; + pPhyInfo->recv_signal_power = rx_pwr_all; /* */ /* (3) Get Signal Quality (EVM) */ /* */ @@ -147,7 +147,7 @@ static void odm_RxPhyStatus92CSeries_Parsing( { u8 SQ, SQ_rpt; - if (pPhyInfo->RxPWDBAll > 40 && !pDM_Odm->bInHctTest) + if (pPhyInfo->rx_pwd_ba11 > 40 && !pDM_Odm->bInHctTest) SQ = 100; else { SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; @@ -162,9 +162,9 @@ static void odm_RxPhyStatus92CSeries_Parsing( } /* DbgPrint("cck SQ = %d\n", SQ); */ - pPhyInfo->SignalQuality = SQ; - pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ; - pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; + pPhyInfo->signal_quality = SQ; + pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_A] = SQ; + pPhyInfo->rx_mimo_signal_quality[ODM_RF_PATH_B] = -1; } } else { /* is OFDM rate */ pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++; @@ -183,17 +183,17 @@ static void odm_RxPhyStatus92CSeries_Parsing( rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain&0x3F)*2) - 110; - pPhyInfo->RxPwr[i] = rx_pwr[i]; + pPhyInfo->rx_pwr[i] = rx_pwr[i]; /* Translate DBM to percentage. */ RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); total_rssi += RSSI; /* RT_DISP(FRX, RX_PHY_SS, ("RF-%d RXPWR =%x RSSI =%d\n", i, rx_pwr[i], RSSI)); */ - pPhyInfo->RxMIMOSignalStrength[i] = (u8) RSSI; + pPhyInfo->rx_mimo_signal_strength[i] = (u8) RSSI; /* Get Rx snr value in DB */ - pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2); + pPhyInfo->rx_snr[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2); } @@ -205,17 +205,17 @@ static void odm_RxPhyStatus92CSeries_Parsing( PWDB_ALL_BT = PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); /* RT_DISP(FRX, RX_PHY_SS, ("PWDB_ALL =%d\n", PWDB_ALL)); */ - pPhyInfo->RxPWDBAll = PWDB_ALL; - /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI =%d\n", pPhyInfo->RxPWDBAll)); */ - pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; - pPhyInfo->RxPower = rx_pwr_all; - pPhyInfo->RecvSignalPower = rx_pwr_all; + pPhyInfo->rx_pwd_ba11 = PWDB_ALL; + /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI =%d\n", pPhyInfo->rx_pwd_ba11)); */ + pPhyInfo->bt_rx_rssi_percentage = PWDB_ALL_BT; + pPhyInfo->rx_power = rx_pwr_all; + pPhyInfo->recv_signal_power = rx_pwr_all; {/* pMgntInfo->CustomerID != RT_CID_819x_Lenovo */ /* */ /* (3)EVM of HT rate */ /* */ - if (pPktinfo->DataRate >= DESC_RATEMCS8 && pPktinfo->DataRate <= DESC_RATEMCS15) + if (pPktinfo->data_rate >= DESC_RATEMCS8 && pPktinfo->data_rate <= DESC_RATEMCS15) Max_spatial_stream = 2; /* both spatial stream make sense */ else Max_spatial_stream = 1; /* only spatial stream 1 makes sense */ @@ -232,9 +232,9 @@ static void odm_RxPhyStatus92CSeries_Parsing( /* if (pPktinfo->bPacketMatchBSSID) */ { if (i == ODM_RF_PATH_A) /* Fill value in RFD, Get the first spatial stream only */ - pPhyInfo->SignalQuality = (u8)(EVM & 0xff); + pPhyInfo->signal_quality = (u8)(EVM & 0xff); - pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff); + pPhyInfo->rx_mimo_signal_quality[i] = (u8)(EVM & 0xff); } } } @@ -249,25 +249,25 @@ static void odm_RxPhyStatus92CSeries_Parsing( #ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING pPhyInfo->SignalStrength = (u8)PWDB_ALL; #else - pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */ + pPhyInfo->signal_strength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */ #endif } else { if (rf_rx_num != 0) { #ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING total_rssi /= rf_rx_num; - pPhyInfo->SignalStrength = (u8)total_rssi; + pPhyInfo->signal_strength = (u8)total_rssi; #else - pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num)); + pPhyInfo->signal_strength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num)); #endif } } - /* DbgPrint("isCCKrate = %d, pPhyInfo->RxPWDBAll = %d, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a = 0x%x\n", */ - /* isCCKrate, pPhyInfo->RxPWDBAll, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a); */ + /* DbgPrint("isCCKrate = %d, pPhyInfo->rx_pwd_ba11 = %d, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a = 0x%x\n", */ + /* isCCKrate, pPhyInfo->rx_pwd_ba11, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a); */ } static void odm_Process_RSSIForDM( - PDM_ODM_T pDM_Odm, PODM_PHY_INFO_T pPhyInfo, PODM_PACKET_INFO_T pPktinfo + PDM_ODM_T pDM_Odm, struct odm_phy_info *pPhyInfo, struct odm_packet_info *pPktinfo ) { @@ -279,22 +279,22 @@ static void odm_Process_RSSIForDM( PSTA_INFO_T pEntry; - if (pPktinfo->StationID == 0xFF) + if (pPktinfo->station_id == 0xFF) return; - pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID]; + pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->station_id]; if (!IS_STA_VALID(pEntry)) return; - if ((!pPktinfo->bPacketMatchBSSID)) + if ((!pPktinfo->bssid_match)) return; - if (pPktinfo->bPacketBeacon) + if (pPktinfo->is_beacon) pDM_Odm->PhyDbgInfo.NumQryBeaconPkt++; - isCCKrate = ((pPktinfo->DataRate <= DESC_RATE11M)) ? true : false; - pDM_Odm->RxRate = pPktinfo->DataRate; + isCCKrate = ((pPktinfo->data_rate <= DESC_RATE11M)) ? true : false; + pDM_Odm->RxRate = pPktinfo->data_rate; /* Statistic for antenna/path diversity------------------ */ if (pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) { @@ -307,28 +307,28 @@ static void odm_Process_RSSIForDM( UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; - if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) { + if (pPktinfo->to_self || pPktinfo->is_beacon) { if (!isCCKrate) { /* ofdm rate */ - if (pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] == 0) { - RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; - pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; + if (pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B] == 0) { + RSSI_Ave = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A]; + pDM_Odm->RSSI_A = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A]; pDM_Odm->RSSI_B = 0; } else { - /* DbgPrint("pRfd->Status.RxMIMOSignalStrength[0] = %d, pRfd->Status.RxMIMOSignalStrength[1] = %d\n", */ - /* pRfd->Status.RxMIMOSignalStrength[0], pRfd->Status.RxMIMOSignalStrength[1]); */ - pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; - pDM_Odm->RSSI_B = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; + /* DbgPrint("pRfd->Status.rx_mimo_signal_strength[0] = %d, pRfd->Status.rx_mimo_signal_strength[1] = %d\n", */ + /* pRfd->Status.rx_mimo_signal_strength[0], pRfd->Status.rx_mimo_signal_strength[1]); */ + pDM_Odm->RSSI_A = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A]; + pDM_Odm->RSSI_B = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B]; if ( - pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A] > - pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] + pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A] > + pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B] ) { - RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; - RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; + RSSI_max = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A]; + RSSI_min = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B]; } else { - RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; - RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; + RSSI_max = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_B]; + RSSI_min = pPhyInfo->rx_mimo_signal_strength[ODM_RF_PATH_A]; } if ((RSSI_max-RSSI_min) < 3) @@ -343,9 +343,9 @@ static void odm_Process_RSSIForDM( /* 1 Process OFDM RSSI */ if (UndecoratedSmoothedOFDM <= 0) /* initialize */ - UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; + UndecoratedSmoothedOFDM = pPhyInfo->rx_pwd_ba11; else { - if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) { + if (pPhyInfo->rx_pwd_ba11 > (u32)UndecoratedSmoothedOFDM) { UndecoratedSmoothedOFDM = ((UndecoratedSmoothedOFDM*(Rx_Smooth_Factor-1)) + RSSI_Ave)/Rx_Smooth_Factor; @@ -360,23 +360,23 @@ static void odm_Process_RSSIForDM( pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0; } else { - RSSI_Ave = pPhyInfo->RxPWDBAll; - pDM_Odm->RSSI_A = (u8) pPhyInfo->RxPWDBAll; + RSSI_Ave = pPhyInfo->rx_pwd_ba11; + pDM_Odm->RSSI_A = (u8) pPhyInfo->rx_pwd_ba11; pDM_Odm->RSSI_B = 0; /* 1 Process CCK RSSI */ if (UndecoratedSmoothedCCK <= 0) /* initialize */ - UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; + UndecoratedSmoothedCCK = pPhyInfo->rx_pwd_ba11; else { - if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) { + if (pPhyInfo->rx_pwd_ba11 > (u32)UndecoratedSmoothedCCK) { UndecoratedSmoothedCCK = ((UndecoratedSmoothedCCK*(Rx_Smooth_Factor-1)) + - pPhyInfo->RxPWDBAll)/Rx_Smooth_Factor; + pPhyInfo->rx_pwd_ba11)/Rx_Smooth_Factor; UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; } else { UndecoratedSmoothedCCK = ((UndecoratedSmoothedCCK*(Rx_Smooth_Factor-1)) + - pPhyInfo->RxPWDBAll)/Rx_Smooth_Factor; + pPhyInfo->rx_pwd_ba11)/Rx_Smooth_Factor; } } pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1; @@ -422,9 +422,9 @@ static void odm_Process_RSSIForDM( /* */ static void ODM_PhyStatusQuery_92CSeries( PDM_ODM_T pDM_Odm, - PODM_PHY_INFO_T pPhyInfo, + struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, - PODM_PACKET_INFO_T pPktinfo + struct odm_packet_info *pPktinfo ) { @@ -436,9 +436,9 @@ static void ODM_PhyStatusQuery_92CSeries( void ODM_PhyStatusQuery( PDM_ODM_T pDM_Odm, - PODM_PHY_INFO_T pPhyInfo, + struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, - PODM_PACKET_INFO_T pPktinfo + struct odm_packet_info *pPktinfo ) { diff --git a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h index f029922d12f0..fdb4f8579ff9 100644 --- a/drivers/staging/rtl8723bs/hal/odm_HWConfig.h +++ b/drivers/staging/rtl8723bs/hal/odm_HWConfig.h @@ -131,9 +131,9 @@ typedef struct _Phy_Status_Rpt_8812 { void ODM_PhyStatusQuery( PDM_ODM_T pDM_Odm, - PODM_PHY_INFO_T pPhyInfo, + struct odm_phy_info *pPhyInfo, u8 *pPhyStatus, - PODM_PACKET_INFO_T pPktinfo + struct odm_packet_info *pPktinfo ); HAL_STATUS ODM_ConfigRFWithTxPwrTrackHeaderFile(PDM_ODM_T pDM_Odm); diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index d6cef9e8378d..0ce9b47d644d 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -433,13 +433,12 @@ s32 rtl8723b_FirmwareDownload(struct adapter *padapter, bool bUsedWoWLANFw) goto exit; } - pFirmware->szFwBuffer = kzalloc(fw->size, GFP_KERNEL); + pFirmware->szFwBuffer = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!pFirmware->szFwBuffer) { rtStatus = _FAIL; goto exit; } - memcpy(pFirmware->szFwBuffer, fw->data, fw->size); pFirmware->ulFwLength = fw->size; release_firmware(fw); if (pFirmware->ulFwLength > FW_8723B_SIZE) { diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c index a71b552eca9a..f6aeb2630398 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c @@ -163,7 +163,7 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter) break; } - /*----Restore RFENV control type----*/; + /*----Restore RFENV control type----*/ switch (eRFPath) { case RF_PATH_A: case RF_PATH_C: diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c index d9a4567ca721..5d5cd4d01156 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c @@ -18,7 +18,6 @@ #include <rtw_debug.h> #include <rtl8723b_hal.h> - static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter) { INIT_LIST_HEAD(&precvbuf->list); @@ -29,9 +28,9 @@ static s32 initrecvbuf(struct recv_buf *precvbuf, struct adapter *padapter) return _SUCCESS; } -static void update_recvframe_attrib( - struct adapter *padapter, union recv_frame *precvframe, struct recv_stat *prxstat -) +static void update_recvframe_attrib(struct adapter *padapter, + union recv_frame *precvframe, + struct recv_stat *prxstat) { struct rx_pkt_attrib *pattrib; struct recv_stat report; @@ -48,7 +47,7 @@ static void update_recvframe_attrib( memset(pattrib, 0, sizeof(struct rx_pkt_attrib)); /* update rx report to recv_frame attribute */ - pattrib->pkt_rpt_type = prxreport->c2h_ind?C2H_PACKET:NORMAL_RX; + pattrib->pkt_rpt_type = prxreport->c2h_ind ? C2H_PACKET : NORMAL_RX; /* DBG_871X("%s: pkt_rpt_type =%d\n", __func__, pattrib->pkt_rpt_type); */ if (pattrib->pkt_rpt_type == NORMAL_RX) { @@ -75,8 +74,9 @@ static void update_recvframe_attrib( pattrib->mdata = (u8)prxreport->md; pattrib->data_rate = (u8)prxreport->rx_rate; - } else + } else { pattrib->pkt_len = (u16)prxreport->pktlen; + } } /* @@ -84,75 +84,92 @@ static void update_recvframe_attrib( *Before calling this function, *precvframe->u.hdr.rx_data should be ready! */ -static void update_recvframe_phyinfo( - union recv_frame *precvframe, struct phy_stat *pphy_status -) +static void update_recvframe_phyinfo(union recv_frame *precvframe, + struct phy_stat *pphy_status) { struct adapter *padapter = precvframe->u.hdr.adapter; struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - PODM_PHY_INFO_T pPHYInfo = (PODM_PHY_INFO_T)(&pattrib->phy_info); + struct hal_com_data *p_hal_data = GET_HAL_DATA(padapter); + struct odm_phy_info *p_phy_info = + (struct odm_phy_info *)(&pattrib->phy_info); u8 *wlanhdr; - ODM_PACKET_INFO_T pkt_info; + u8 *my_bssid; + u8 *rx_bssid; + u8 *rx_ra; + u8 *my_hwaddr; u8 *sa = NULL; + + struct odm_packet_info pkt_info = { + .data_rate = 0x00, + .station_id = 0x00, + .bssid_match = false, + .to_self = false, + .is_beacon = false, + }; + /* _irqL irqL; */ struct sta_priv *pstapriv; struct sta_info *psta; - pkt_info.bPacketMatchBSSID = false; - pkt_info.bPacketToSelf = false; - pkt_info.bPacketBeacon = false; - - wlanhdr = get_recvframe_data(precvframe); + my_bssid = get_bssid(&padapter->mlmepriv); + rx_bssid = get_hdr_bssid(wlanhdr); + pkt_info.bssid_match = ((!IsFrameTypeCtrl(wlanhdr)) && + !pattrib->icv_err && !pattrib->crc_err && + !ether_addr_equal(rx_bssid, my_bssid)); - pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) && - !pattrib->icv_err && !pattrib->crc_err && - !memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN)); + rx_ra = get_ra(wlanhdr); + my_hwaddr = myid(&padapter->eeprompriv); + pkt_info.to_self = pkt_info.bssid_match && + !ether_addr_equal(rx_ra, my_hwaddr); - pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID && (!memcmp(get_ra(wlanhdr), myid(&padapter->eeprompriv), ETH_ALEN)); - pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID && (GetFrameSubType(wlanhdr) == WIFI_BEACON); + pkt_info.is_beacon = pkt_info.bssid_match && + (GetFrameSubType(wlanhdr) == WIFI_BEACON); sa = get_ta(wlanhdr); - pkt_info.StationID = 0xFF; + pkt_info.station_id = 0xFF; pstapriv = &padapter->stapriv; psta = rtw_get_stainfo(pstapriv, sa); if (psta) { - pkt_info.StationID = psta->mac_id; - /* DBG_8192C("%s ==> StationID(%d)\n", __func__, pkt_info.StationID); */ + pkt_info.station_id = psta->mac_id; + /* DBG_8192C("%s ==> StationID(%d)\n", + * __func__, pkt_info.station_id); */ } - pkt_info.DataRate = pattrib->data_rate; + pkt_info.data_rate = pattrib->data_rate; /* rtl8723b_query_rx_phy_status(precvframe, pphy_status); */ - /* spin_lock_bh(&pHalData->odm_stainfo_lock); */ - ODM_PhyStatusQuery(&pHalData->odmpriv, pPHYInfo, (u8 *)pphy_status, &(pkt_info)); + /* spin_lock_bh(&p_hal_data->odm_stainfo_lock); */ + ODM_PhyStatusQuery(&p_hal_data->odmpriv, p_phy_info, + (u8 *)pphy_status, &(pkt_info)); if (psta) psta->rssi = pattrib->phy_info.RecvSignalPower; - /* spin_unlock_bh(&pHalData->odm_stainfo_lock); */ + /* spin_unlock_bh(&p_hal_data->odm_stainfo_lock); */ precvframe->u.hdr.psta = NULL; if ( - pkt_info.bPacketMatchBSSID && + pkt_info.bssid_match && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) ) { if (psta) { precvframe->u.hdr.psta = psta; rtl8723b_process_phy_info(padapter, precvframe); } - } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) { - if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == true) + } else if (pkt_info.to_self || pkt_info.is_beacon) { + u32 adhoc_state = WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE; + if (check_fwstate(&padapter->mlmepriv, adhoc_state)) if (psta) precvframe->u.hdr.psta = psta; rtl8723b_process_phy_info(padapter, precvframe); } } -static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, u8 *pbuf, u16 length) +static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, + u8 *pbuf, u16 length) { - u8 *tmpBuf = NULL; + u8 *tmp = NULL; u8 res = false; if (length == 0) @@ -160,85 +177,127 @@ static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, u8 *pbuf, u16 /* DBG_871X("+%s() length =%d\n", __func__, length); */ - tmpBuf = rtw_zmalloc(length); - if (tmpBuf == NULL) + tmp = rtw_zmalloc(length); + if (tmp == NULL) return; - memcpy(tmpBuf, pbuf, length); + memcpy(tmp, pbuf, length); - res = rtw_c2h_packet_wk_cmd(padapter, tmpBuf, length); + res = rtw_c2h_packet_wk_cmd(padapter, tmp, length); if (res == false) - kfree(tmpBuf); + kfree(tmp); /* DBG_871X("-%s res(%d)\n", __func__, res); */ return; } +static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv, + struct recv_buf *precvbuf) +{ + union recv_frame *precvframe; + + precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue); + if (!precvframe) { + DBG_8192C("%s: no enough recv frame!\n", __func__); + rtw_enqueue_recvbuf_to_head(precvbuf, + &precvpriv->recv_buf_pending_queue); + + /* The case of can't allocte recvframe should be temporary, */ + /* schedule again and hope recvframe is available next time. */ + tasklet_schedule(&precvpriv->recv_tasklet); + } + + return precvframe; +} + +static inline bool rx_crc_err(struct recv_priv *precvpriv, + struct hal_com_data *p_hal_data, + struct rx_pkt_attrib *pattrib, + union recv_frame *precvframe) +{ + /* fix Hardware RX data error, drop whole recv_buffer */ + if ((!(p_hal_data->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) { + DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n", + __func__, __LINE__); + rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); + return true; + } + + return false; +} + +static inline bool pkt_exceeds_tail(struct recv_priv *precvpriv, + u8 *end, u8 *tail, + union recv_frame *precvframe) +{ + if (end > tail) { + DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", + __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail); + rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); + return true; + } + + return false; +} + static void rtl8723bs_recv_tasklet(void *priv) { struct adapter *padapter; - struct hal_com_data *pHalData; + struct hal_com_data *p_hal_data; struct recv_priv *precvpriv; struct recv_buf *precvbuf; union recv_frame *precvframe; struct rx_pkt_attrib *pattrib; + struct __queue *recv_buf_queue; u8 *ptr; u32 pkt_offset, skb_len, alloc_sz; _pkt *pkt_copy = NULL; u8 shift_sz = 0, rx_report_sz = 0; - padapter = priv; - pHalData = GET_HAL_DATA(padapter); + p_hal_data = GET_HAL_DATA(padapter); precvpriv = &padapter->recvpriv; + recv_buf_queue = &precvpriv->recv_buf_pending_queue; do { - precvbuf = rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue); - if (NULL == precvbuf) + precvbuf = rtw_dequeue_recvbuf(recv_buf_queue); + if (!precvbuf) break; ptr = precvbuf->pdata; while (ptr < precvbuf->ptail) { - precvframe = rtw_alloc_recvframe(&precvpriv->free_recv_queue); - if (precvframe == NULL) { - DBG_8192C("%s: no enough recv frame!\n", __func__); - rtw_enqueue_recvbuf_to_head(precvbuf, &precvpriv->recv_buf_pending_queue); - - /* The case of can't allocte recvframe should be temporary, */ - /* schedule again and hope recvframe is available next time. */ - tasklet_schedule(&precvpriv->recv_tasklet); + precvframe = try_alloc_recvframe(precvpriv, precvbuf); + if(!precvframe) return; - } /* rx desc parsing */ - update_recvframe_attrib(padapter, precvframe, (struct recv_stat *)ptr); + update_recvframe_attrib(padapter, precvframe, + (struct recv_stat *)ptr); pattrib = &precvframe->u.hdr.attrib; - /* fix Hardware RX data error, drop whole recv_buffer */ - if ((!(pHalData->ReceiveConfig & RCR_ACRC32)) && pattrib->crc_err) { - DBG_8192C("%s()-%d: RX Warning! rx CRC ERROR !!\n", __func__, __LINE__); - rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); + if(rx_crc_err(precvpriv, p_hal_data, + pattrib, precvframe)) break; - } rx_report_sz = RXDESC_SIZE + pattrib->drvinfo_sz; - pkt_offset = rx_report_sz + pattrib->shift_sz + pattrib->pkt_len; + pkt_offset = rx_report_sz + + pattrib->shift_sz + + pattrib->pkt_len; - if ((ptr + pkt_offset) > precvbuf->ptail) { - DBG_8192C("%s()-%d: : next pkt len(%p,%d) exceed ptail(%p)!\n", __func__, __LINE__, ptr, pkt_offset, precvbuf->ptail); - rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); + if(pkt_exceeds_tail(precvpriv, ptr + pkt_offset, + precvbuf->ptail, precvframe)) break; - } if ((pattrib->crc_err) || (pattrib->icv_err)) { - { - DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n", __func__, pattrib->crc_err, pattrib->icv_err); - } - rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); + DBG_8192C("%s: crc_err =%d icv_err =%d, skip!\n", + __func__, pattrib->crc_err, + pattrib->icv_err); + rtw_free_recvframe(precvframe, + &precvpriv->free_recv_queue); } else { /* Modified by Albert 20101213 */ /* For 8 bytes IP header alignment. */ @@ -289,7 +348,7 @@ static void rtl8723bs_recv_tasklet(void *priv) skb_reset_tail_pointer(pkt_clone); precvframe->u.hdr.rx_head = precvframe->u.hdr.rx_data = precvframe->u.hdr.rx_tail = pkt_clone->data; - precvframe->u.hdr.rx_end = pkt_clone->data + skb_len; + precvframe->u.hdr.rx_end = pkt_clone->data + skb_len; } else { DBG_8192C("%s: rtw_skb_clone fail\n", __func__); rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); @@ -300,14 +359,14 @@ static void rtl8723bs_recv_tasklet(void *priv) recvframe_put(precvframe, skb_len); /* recvframe_pull(precvframe, drvinfo_sz + RXDESC_SIZE); */ - if (pHalData->ReceiveConfig & RCR_APPFCS) + if (p_hal_data->ReceiveConfig & RCR_APPFCS) recvframe_pull_tail(precvframe, IEEE80211_FCS_LEN); /* move to drv info position */ ptr += RXDESC_SIZE; /* update drv info */ - if (pHalData->ReceiveConfig & RCR_APP_BA_SSN) { + if (p_hal_data->ReceiveConfig & RCR_APP_BA_SSN) { /* rtl8723s_update_bassn(padapter, pdrvinfo); */ ptr += 4; } @@ -337,7 +396,6 @@ static void rtl8723bs_recv_tasklet(void *priv) rtl8723bs_c2h_packet_handler(padapter, precvframe->u.hdr.rx_data, pattrib->pkt_len); rtw_free_recvframe(precvframe, &precvpriv->free_recv_queue); - } } @@ -350,7 +408,6 @@ static void rtl8723bs_recv_tasklet(void *priv) rtw_enqueue_recvbuf(precvbuf, &precvpriv->free_recv_buf_queue); } while (1); - } /* @@ -366,7 +423,6 @@ s32 rtl8723bs_init_recv_priv(struct adapter *padapter) struct recv_priv *precvpriv; struct recv_buf *precvbuf; - res = _SUCCESS; precvpriv = &padapter->recvpriv; @@ -463,7 +519,6 @@ void rtl8723bs_free_recv_priv(struct adapter *padapter) struct recv_priv *precvpriv; struct recv_buf *precvbuf; - precvpriv = &padapter->recvpriv; /* 3 1. kill tasklet */ diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index 32129ac8e169..16b81b1a3f33 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -692,9 +692,9 @@ int rtw_suspend_wow(struct adapter *padapter); int rtw_resume_process_wow(struct adapter *padapter); #endif -__inline static u8 *myid(struct eeprom_priv *peepriv) +static inline u8 *myid(struct eeprom_priv *peepriv) { - return (peepriv->mac_addr); + return peepriv->mac_addr; } /* HCI Related header file */ diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index 73ce63770c3c..c8e5251c2760 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -84,10 +84,6 @@ enum { #define IEEE_PARAM_IEEE_802_1X 6 #define IEEE_PARAM_WPAX_SELECT 7 -#define AUTH_ALG_OPEN_SYSTEM 0x1 -#define AUTH_ALG_SHARED_KEY 0x2 -#define AUTH_ALG_LEAP 0x00000004 - #define IEEE_MLME_STA_DEAUTH 1 #define IEEE_MLME_STA_DISASSOC 2 @@ -276,20 +272,6 @@ struct sta_data{ u64 tx_drops; }; -#define IEEE80211_DATA_LEN 2304 -/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section - 6.2.1.1.2. - - The figure in section 7.1.2 suggests a body size of up to 2312 - bytes is allowed, which is a bit confusing, I suspect this - represents the 2304 bytes of real data, plus a possible 8 bytes of - WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ - - -#define IEEE80211_HLEN 30 -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - - /* this is stolen from ipw2200 driver */ #define IEEE_IBSS_MAC_HASH_SIZE 31 @@ -317,75 +299,11 @@ enum eap_type { EAPOL_ENCAP_ASF_ALERT }; -#define IEEE80211_3ADDR_LEN 24 -#define IEEE80211_4ADDR_LEN 30 #define IEEE80211_FCS_LEN 4 #define MIN_FRAG_THRESHOLD 256U #define MAX_FRAG_THRESHOLD 2346U -/* Frame control field constants */ -#define RTW_IEEE80211_FCTL_VERS 0x0003 -#define RTW_IEEE80211_FCTL_FTYPE 0x000c -#define RTW_IEEE80211_FCTL_STYPE 0x00f0 -#define RTW_IEEE80211_FCTL_TODS 0x0100 -#define RTW_IEEE80211_FCTL_FROMDS 0x0200 -#define RTW_IEEE80211_FCTL_MOREFRAGS 0x0400 -#define RTW_IEEE80211_FCTL_RETRY 0x0800 -#define RTW_IEEE80211_FCTL_PM 0x1000 -#define RTW_IEEE80211_FCTL_MOREDATA 0x2000 -#define RTW_IEEE80211_FCTL_PROTECTED 0x4000 -#define RTW_IEEE80211_FCTL_ORDER 0x8000 -#define RTW_IEEE80211_FCTL_CTL_EXT 0x0f00 - -#define RTW_IEEE80211_FTYPE_MGMT 0x0000 -#define RTW_IEEE80211_FTYPE_CTL 0x0004 -#define RTW_IEEE80211_FTYPE_DATA 0x0008 -#define RTW_IEEE80211_FTYPE_EXT 0x000c - -/* management */ -#define RTW_IEEE80211_STYPE_ASSOC_REQ 0x0000 -#define RTW_IEEE80211_STYPE_ASSOC_RESP 0x0010 -#define RTW_IEEE80211_STYPE_REASSOC_REQ 0x0020 -#define RTW_IEEE80211_STYPE_REASSOC_RESP 0x0030 -#define RTW_IEEE80211_STYPE_PROBE_REQ 0x0040 -#define RTW_IEEE80211_STYPE_PROBE_RESP 0x0050 -#define RTW_IEEE80211_STYPE_BEACON 0x0080 -#define RTW_IEEE80211_STYPE_ATIM 0x0090 -#define RTW_IEEE80211_STYPE_DISASSOC 0x00A0 -#define RTW_IEEE80211_STYPE_AUTH 0x00B0 -#define RTW_IEEE80211_STYPE_DEAUTH 0x00C0 -#define RTW_IEEE80211_STYPE_ACTION 0x00D0 - -/* control */ -#define RTW_IEEE80211_STYPE_CTL_EXT 0x0060 -#define RTW_IEEE80211_STYPE_BACK_REQ 0x0080 -#define RTW_IEEE80211_STYPE_BACK 0x0090 -#define RTW_IEEE80211_STYPE_PSPOLL 0x00A0 -#define RTW_IEEE80211_STYPE_RTS 0x00B0 -#define RTW_IEEE80211_STYPE_CTS 0x00C0 -#define RTW_IEEE80211_STYPE_ACK 0x00D0 -#define RTW_IEEE80211_STYPE_CFEND 0x00E0 -#define RTW_IEEE80211_STYPE_CFENDACK 0x00F0 - -/* data */ -#define RTW_IEEE80211_STYPE_DATA 0x0000 -#define RTW_IEEE80211_STYPE_DATA_CFACK 0x0010 -#define RTW_IEEE80211_STYPE_DATA_CFPOLL 0x0020 -#define RTW_IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 -#define RTW_IEEE80211_STYPE_NULLFUNC 0x0040 -#define RTW_IEEE80211_STYPE_CFACK 0x0050 -#define RTW_IEEE80211_STYPE_CFPOLL 0x0060 -#define RTW_IEEE80211_STYPE_CFACKPOLL 0x0070 -#define RTW_IEEE80211_STYPE_QOS_DATA 0x0080 -#define RTW_IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 -#define RTW_IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 -#define RTW_IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 -#define RTW_IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 -#define RTW_IEEE80211_STYPE_QOS_CFACK 0x00D0 -#define RTW_IEEE80211_STYPE_QOS_CFPOLL 0x00E0 -#define RTW_IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 - /* sequence control field */ #define RTW_IEEE80211_SCTL_FRAG 0x000F #define RTW_IEEE80211_SCTL_SEQ 0xFFF0 @@ -426,8 +344,8 @@ struct ieee80211_snap_hdr { #define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) -#define WLAN_FC_GET_TYPE(fc) ((fc) & RTW_IEEE80211_FCTL_FTYPE) -#define WLAN_FC_GET_STYPE(fc) ((fc) & RTW_IEEE80211_FCTL_STYPE) +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) #define WLAN_QC_GET_TID(qc) ((qc) & 0x0f) @@ -435,91 +353,23 @@ struct ieee80211_snap_hdr { #define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_IEEE80211_SCTL_SEQ) /* Authentication algorithms */ -#define WLAN_AUTH_OPEN 0 -#define WLAN_AUTH_SHARED_KEY 1 - -#define WLAN_AUTH_CHALLENGE_LEN 128 - #define WLAN_CAPABILITY_BSS (1<<0) -#define WLAN_CAPABILITY_IBSS (1<<1) -#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) -#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) -#define WLAN_CAPABILITY_PRIVACY (1<<4) -#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) -#define WLAN_CAPABILITY_PBCC (1<<6) -#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) #define WLAN_CAPABILITY_SHORT_SLOT (1<<10) -/* Status codes */ -#define WLAN_STATUS_SUCCESS 0 -#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 -#define WLAN_STATUS_CAPS_UNSUPPORTED 10 -#define WLAN_STATUS_REASSOC_NO_ASSOC 11 -#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 -#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 -#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 -#define WLAN_STATUS_CHALLENGE_FAIL 15 -#define WLAN_STATUS_AUTH_TIMEOUT 16 -#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 -#define WLAN_STATUS_ASSOC_DENIED_RATES 18 /* 802.11b */ #define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 -#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 -#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 /* Reason codes */ -#define WLAN_REASON_UNSPECIFIED 1 -#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 -#define WLAN_REASON_DEAUTH_LEAVING 3 -#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 -#define WLAN_REASON_DISASSOC_AP_BUSY 5 -#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 -#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 -#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 -#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 #define WLAN_REASON_ACTIVE_ROAM 65533 #define WLAN_REASON_JOIN_WRONG_CHANNEL 65534 #define WLAN_REASON_EXPIRATION_CHK 65535 -/* Information Element IDs */ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARAMS 2 -#define WLAN_EID_DS_PARAMS 3 -#define WLAN_EID_CF_PARAMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARAMS 6 -#define WLAN_EID_CHALLENGE 16 -/* EIDs defined by IEEE 802.11h - START */ -#define WLAN_EID_PWR_CONSTRAINT 32 -#define WLAN_EID_PWR_CAPABILITY 33 -#define WLAN_EID_TPC_REQUEST 34 -#define WLAN_EID_TPC_REPORT 35 -#define WLAN_EID_SUPPORTED_CHANNELS 36 -#define WLAN_EID_CHANNEL_SWITCH 37 -#define WLAN_EID_MEASURE_REQUEST 38 -#define WLAN_EID_MEASURE_REPORT 39 -#define WLAN_EID_QUITE 40 -#define WLAN_EID_IBSS_DFS 41 /* EIDs defined by IEEE 802.11h - END */ -#define WLAN_EID_ERP_INFO 42 #define WLAN_EID_HT_CAP 45 -#define WLAN_EID_RSN 48 -#define WLAN_EID_EXT_SUPP_RATES 50 -#define WLAN_EID_MOBILITY_DOMAIN 54 -#define WLAN_EID_FAST_BSS_TRANSITION 55 -#define WLAN_EID_TIMEOUT_INTERVAL 56 -#define WLAN_EID_RIC_DATA 57 -#define WLAN_EID_HT_OPERATION 61 -#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_20_40_BSS_COEXISTENCE 72 #define WLAN_EID_20_40_BSS_INTOLERANT 73 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 -#define WLAN_EID_MMIE 76 -#define WLAN_EID_VENDOR_SPECIFIC 221 #define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC) -#define WLAN_EID_VHT_CAPABILITY 191 -#define WLAN_EID_VHT_OPERATION 192 #define WLAN_EID_VHT_OP_MODE_NOTIFY 199 #define IEEE80211_MGMT_HDR_LEN 24 diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h index 00b3d92c9f51..2e4f12b54929 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h @@ -299,7 +299,7 @@ struct wifidirect_info{ struct tdls_ss_record{ /* signal strength record */ u8 macaddr[ETH_ALEN]; - u8 RxPWDBAll; + u8 rx_pwd_ba11; u8 is_tdls_sta; /* true: direct link sta, false: else */ }; diff --git a/drivers/staging/rtl8723bs/include/rtw_recv.h b/drivers/staging/rtl8723bs/include/rtw_recv.h index 71039ca79e4b..d4986f5685c5 100644 --- a/drivers/staging/rtl8723bs/include/rtw_recv.h +++ b/drivers/staging/rtl8723bs/include/rtw_recv.h @@ -99,20 +99,20 @@ struct signal_stat { }; struct phy_info { - u8 RxPWDBAll; + u8 rx_pwd_ba11; u8 SignalQuality; /* in 0-100 index. */ - s8 RxMIMOSignalQuality[4]; /* per-path's EVM */ + s8 rx_mimo_signal_quality[4]; /* per-path's EVM */ u8 RxMIMOEVMdbm[4]; /* per-path's EVM dbm */ - u8 RxMIMOSignalStrength[4];/* in 0~100 index */ + u8 rx_mimo_signal_strength[4];/* in 0~100 index */ u16 Cfo_short[4]; /* per-path's Cfo_short */ u16 Cfo_tail[4]; /* per-path's Cfo_tail */ s8 RxPower; /* in dBm Translate from PWdB */ s8 RecvSignalPower;/* Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */ - u8 BTRxRSSIPercentage; + u8 bt_rx_rssi_percentage; u8 SignalStrength; /* in 0-100 index. */ s8 RxPwr[4]; /* per-path's pwdb */ @@ -187,7 +187,7 @@ struct rx_pkt_attrib { u8 signal_qual; s8 rx_mimo_signal_qual[2]; u8 signal_strength; - u32 RxPWDBAll; + u32 rx_pwd_ba11; s32 RecvSignalPower; */ struct phy_info phy_info; diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 51d48de24a24..46bc2e512557 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -14,6 +14,7 @@ ******************************************************************************/ #define _IOCTL_CFG80211_C_ +#include <linux/etherdevice.h> #include <drv_types.h> #include <rtw_debug.h> #include <linux/jiffies.h> @@ -2391,7 +2392,7 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, { if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ - memset(psecuritypriv->PMKIDList[index].Bssid, 0x00, ETH_ALEN); + eth_zero_addr(psecuritypriv->PMKIDList[index].Bssid); memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, WLAN_PMKID_LEN); psecuritypriv->PMKIDList[index].bUsed = false; bMatched = true; @@ -2516,7 +2517,7 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_de dot11_hdr = (struct ieee80211_hdr *)skb->data; frame_control = le16_to_cpu(dot11_hdr->frame_control); /* Check if the QoS bit is set */ - if ((frame_control & RTW_IEEE80211_FCTL_FTYPE) == RTW_IEEE80211_FTYPE_DATA) { + if ((frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { /* Check if this ia a Wireless Distribution System (WDS) frame * which has 4 MAC addresses */ @@ -2544,8 +2545,8 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_de return ret; } - else if ((frame_control & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)) - == (RTW_IEEE80211_FTYPE_MGMT|RTW_IEEE80211_STYPE_ACTION) + else if ((frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) + == (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION) ) { /* only for action frames */ @@ -2606,7 +2607,7 @@ static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_de } else { - DBG_8192C("frame_control = 0x%x\n", frame_control & (RTW_IEEE80211_FCTL_FTYPE|RTW_IEEE80211_FCTL_STYPE)); + DBG_8192C("frame_control = 0x%x\n", frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)); } @@ -3255,7 +3256,7 @@ static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy, struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - u8 ret; + int ret; if (padapter->bup == false) { DBG_871X("%s: net device is down.\n", __func__); diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index cc18d0ad7d7b..b26533983864 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -14,6 +14,7 @@ ******************************************************************************/ #define _IOCTL_LINUX_C_ +#include <linux/etherdevice.h> #include <drv_types.h> #include <rtw_debug.h> #include <rtw_mp.h> @@ -124,7 +125,7 @@ void rtw_indicate_wx_disassoc_event(struct adapter *padapter) memset(&wrqu, 0, sizeof(union iwreq_data)); wrqu.ap_addr.sa_family = ARPHRD_ETHER; - memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + eth_zero_addr(wrqu.ap_addr.sa_data); } /* @@ -475,26 +476,26 @@ static int wpa_set_auth_algs(struct net_device *dev, u32 value) struct adapter *padapter = (struct adapter *) rtw_netdev_priv(dev); int ret = 0; - if ((value & AUTH_ALG_SHARED_KEY) && (value & AUTH_ALG_OPEN_SYSTEM)) { - DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n", value); + if ((value & WLAN_AUTH_SHARED_KEY) && (value & WLAN_AUTH_OPEN)) { + DBG_871X("wpa_set_auth_algs, WLAN_AUTH_SHARED_KEY and WLAN_AUTH_OPEN [value:0x%x]\n", value); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto; - } else if (value & AUTH_ALG_SHARED_KEY) { - DBG_871X("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY [value:0x%x]\n", value); + } else if (value & WLAN_AUTH_SHARED_KEY) { + DBG_871X("wpa_set_auth_algs, WLAN_AUTH_SHARED_KEY [value:0x%x]\n", value); padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared; - } else if (value & AUTH_ALG_OPEN_SYSTEM) { - DBG_871X("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n"); + } else if (value & WLAN_AUTH_OPEN) { + DBG_871X("wpa_set_auth_algs, WLAN_AUTH_OPEN\n"); /* padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; */ if (padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK) { padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; } - } else if (value & AUTH_ALG_LEAP) { - DBG_871X("wpa_set_auth_algs, AUTH_ALG_LEAP\n"); + } else if (value & WLAN_AUTH_LEAP) { + DBG_871X("wpa_set_auth_algs, WLAN_AUTH_LEAP\n"); } else { DBG_871X("wpa_set_auth_algs, error!\n"); ret = -EINVAL; @@ -1080,7 +1081,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev, for (j = 0 ; j<NUM_PMKID_CACHE; j++) { if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ - memset(psecuritypriv->PMKIDList[ j ].Bssid, 0x00, ETH_ALEN); + eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid); psecuritypriv->PMKIDList[ j ].bUsed = false; break; } @@ -1294,7 +1295,7 @@ static int rtw_wx_get_wap(struct net_device *dev, wrqu->ap_addr.sa_family = ARPHRD_ETHER; - memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + eth_zero_addr(wrqu->ap_addr.sa_data); RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_wap\n")); @@ -1303,7 +1304,7 @@ static int rtw_wx_get_wap(struct net_device *dev, ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == true)) { memcpy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress, ETH_ALEN); } else { - memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); + eth_zero_addr(wrqu->ap_addr.sa_data); } return 0; @@ -2130,75 +2131,65 @@ static int rtw_wx_set_gen_ie(struct net_device *dev, } static int rtw_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); struct iw_param *param = (struct iw_param*)&(wrqu->param); int ret = 0; switch (param->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: break; case IW_AUTH_CIPHER_PAIRWISE: - break; case IW_AUTH_CIPHER_GROUP: - break; case IW_AUTH_KEY_MGMT: /* * ??? does not use these parameters */ break; - case IW_AUTH_TKIP_COUNTERMEASURES: - { - if (param->value) { - /* wpa_supplicant is enabling the tkip countermeasure. */ + /* wpa_supplicant is setting the tkip countermeasure. */ + if (param->value) /* enabling */ padapter->securitypriv.btkip_countermeasure = true; - } else { - /* wpa_supplicant is disabling the tkip countermeasure. */ + else /* disabling */ padapter->securitypriv.btkip_countermeasure = false; - } break; - } case IW_AUTH_DROP_UNENCRYPTED: - { - /* HACK: - * - * wpa_supplicant calls set_wpa_enabled when the driver - * is loaded and unloaded, regardless of if WPA is being - * used. No other calls are made which can be used to - * determine if encryption will be used or not prior to - * association being expected. If encryption is not being - * used, drop_unencrypted is set to false, else true -- we - * can use this to determine if the CAP_PRIVACY_ON bit should - * be set. - */ - - if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) { - break;/* it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, */ - /* then it needn't reset it; */ - } - - if (param->value) { - padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; - padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; - padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; - padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ - padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeOpen; - } + /* HACK: + * + * wpa_supplicant calls set_wpa_enabled when the driver + * is loaded and unloaded, regardless of if WPA is being + * used. No other calls are made which can be used to + * determine if encryption will be used or not prior to + * association being expected. If encryption is not being + * used, drop_unencrypted is set to false, else true -- we + * can use this to determine if the CAP_PRIVACY_ON bit should + * be set. + */ + /* + * This means init value, or using wep, ndisencryptstatus = + * Ndis802_11Encryption1Enabled, then it needn't reset it; + */ + if (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled) break; + + if (param->value) { + padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; + padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; + padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; + padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */ + padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeOpen; } + break; case IW_AUTH_80211_AUTH_ALG: - /* * It's the starting point of a link layer connection using wpa_supplicant - */ + */ if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { LeaveAllPowerSaveMode(padapter); rtw_disassoc_cmd(padapter, 500, false); @@ -2207,11 +2198,8 @@ static int rtw_wx_set_auth(struct net_device *dev, rtw_free_assoc_resources(padapter, 1); } - ret = wpa_set_auth_algs(dev, (u32)param->value); - break; - case IW_AUTH_WPA_ENABLED: break; case IW_AUTH_RX_UNENCRYPTED_EAPOL: @@ -2221,6 +2209,7 @@ static int rtw_wx_set_auth(struct net_device *dev, default: return -EOPNOTSUPP; } + return ret; } diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index e804b430931c..b43e24c3a23a 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -43,6 +43,7 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv) { sint i; union recv_frame *precvframe; + precvframe = (union recv_frame*) precvpriv->precv_frame_buf; for (i = 0; i < NR_RECVFRAME; i++) @@ -181,11 +182,11 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt pkt->dev = padapter->pnetdev; #ifdef CONFIG_TCP_CSUM_OFFLOAD_RX - if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) { + if ((pattrib->tcpchk_valid == 1) && (pattrib->tcp_chkrpt == 1)) pkt->ip_summed = CHECKSUM_UNNECESSARY; - } else { + else pkt->ip_summed = CHECKSUM_NONE; - } + #else /* !CONFIG_TCP_CSUM_OFFLOAD_RX */ pkt->ip_summed = CHECKSUM_NONE; #endif /* CONFIG_TCP_CSUM_OFFLOAD_RX */ diff --git a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c b/drivers/staging/rtl8723bs/os_dep/rtw_proc.c index 9a885e626d1c..49c8684dc25b 100644 --- a/drivers/staging/rtl8723bs/os_dep/rtw_proc.c +++ b/drivers/staging/rtl8723bs/os_dep/rtw_proc.c @@ -19,7 +19,7 @@ #ifdef PROC_DEBUG -static struct proc_dir_entry *rtw_proc = NULL; +static struct proc_dir_entry *rtw_proc; #define RTW_PROC_NAME "rtl8723bs" @@ -142,7 +142,7 @@ int rtw_drv_proc_init(void) goto exit; } - for (i = 0;i<drv_proc_hdls_num;i++) { + for (i = 0; i < drv_proc_hdls_num; i++) { entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_fops, (void *)i); if (!entry) { rtw_warn_on(1); @@ -163,7 +163,7 @@ void rtw_drv_proc_deinit(void) if (rtw_proc == NULL) return; - for (i = 0;i<drv_proc_hdls_num;i++) + for (i = 0; i < drv_proc_hdls_num; i++) remove_proc_entry(drv_proc_hdls[i].name, rtw_proc); remove_proc_entry(RTW_PROC_NAME, get_proc_net); @@ -341,7 +341,7 @@ static int proc_get_cam_cache(struct seq_file *m, void *v) /* "MK", "GK", "MFB", "valid" */ ); - for (i = 0;i<32;i++) { + for (i = 0; i < 32; i++) { if (dvobj->cam_cache[i].ctrl != 0) DBG_871X_SEL_NL(m, "%2u 0x%04x "MAC_FMT" "KEY_FMT" %3u %-7s" /* %2u %2u 0x%02x %5u" */ @@ -663,7 +663,7 @@ static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev) adapter->dir_odm = dir_odm; - for (i = 0;i<odm_proc_hdls_num;i++) { + for (i = 0; i < odm_proc_hdls_num; i++) { entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_fops, (void *)i); if (!entry) { rtw_warn_on(1); @@ -687,7 +687,7 @@ static void rtw_odm_proc_deinit(struct adapter *adapter) return; } - for (i = 0;i<odm_proc_hdls_num;i++) + for (i = 0; i < odm_proc_hdls_num; i++) remove_proc_entry(odm_proc_hdls[i].name, dir_odm); remove_proc_entry("odm", adapter->dir_dev); @@ -721,7 +721,7 @@ struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev) adapter->dir_dev = dir_dev; - for (i = 0;i<adapter_proc_hdls_num;i++) { + for (i = 0; i < adapter_proc_hdls_num; i++) { entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_fops, (void *)i); if (!entry) { rtw_warn_on(1); @@ -749,7 +749,7 @@ void rtw_adapter_proc_deinit(struct net_device *dev) return; } - for (i = 0;i<adapter_proc_hdls_num;i++) + for (i = 0; i < adapter_proc_hdls_num; i++) remove_proc_entry(adapter_proc_hdls[i].name, dir_dev); rtw_odm_proc_deinit(adapter); @@ -773,7 +773,7 @@ void rtw_adapter_proc_replace(struct net_device *dev) return; } - for (i = 0;i<adapter_proc_hdls_num;i++) + for (i = 0; i < adapter_proc_hdls_num; i++) remove_proc_entry(adapter_proc_hdls[i].name, dir_dev); rtw_odm_proc_deinit(adapter); diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index 943324877707..99c407ba0874 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -337,7 +337,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct struct adapter *padapter = NULL; PSDIO_DATA psdio = &dvobj->intf_data; - padapter = (struct adapter *)vzalloc(sizeof(*padapter)); + padapter = vzalloc(sizeof(*padapter)); if (padapter == NULL) { goto exit; } diff --git a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c index f29e110f9bdb..21e1b811f997 100644 --- a/drivers/staging/rtl8723bs/os_dep/xmit_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/xmit_linux.c @@ -64,9 +64,7 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitb if (alloc_sz > 0) { pxmitbuf->pallocated_buf = rtw_zmalloc(alloc_sz); if (pxmitbuf->pallocated_buf == NULL) - { return _FAIL; - } pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); } @@ -90,10 +88,8 @@ void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt) queue = skb_get_queue_mapping(pkt); if (padapter->registrypriv.wifi_spec) { if (__netif_subqueue_stopped(padapter->pnetdev, queue) && - (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) - { + (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD)) netif_wake_subqueue(padapter->pnetdev, queue); - } } else { if (__netif_subqueue_stopped(padapter->pnetdev, queue)) netif_wake_subqueue(padapter->pnetdev, queue); @@ -177,18 +173,15 @@ static int rtw_mlcst2unicst(struct adapter *padapter, struct sk_buff *skb) for (i = 0; i < chk_alive_num; i++) { psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); - if (!(psta->state & _FW_LINKED)) - { + if (!(psta->state & _FW_LINKED)) { DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_fw_linked); continue; } /* avoid come from STA1 and send back STA1 */ - if (!memcmp(psta->hwaddr, &skb->data[6], 6) - || !memcmp(psta->hwaddr, null_addr, 6) - || !memcmp(psta->hwaddr, bc_addr, 6) - ) - { + if (!memcmp(psta->hwaddr, &skb->data[6], 6) || + !memcmp(psta->hwaddr, null_addr, 6) || + !memcmp(psta->hwaddr, bc_addr, 6)) { DBG_COUNTER(padapter->tx_logs.os_tx_m2u_ignore_self); continue; } @@ -248,14 +241,11 @@ int _rtw_xmit_entry(_pkt *pkt, _nic_hdl pnetdev) || is_broadcast_mac_addr(pkt->data) #endif ) - && (padapter->registrypriv.wifi_spec == 0) - ) - { + && padapter->registrypriv.wifi_spec == 0) { if (pxmitpriv->free_xmitframe_cnt > (NR_XMITFRAME/4)) { res = rtw_mlcst2unicst(padapter, pkt); - if (res == true) { + if (res == true) goto exit; - } } else { /* DBG_871X("Stop M2U(%d, %d)! ", pxmitpriv->free_xmitframe_cnt, pxmitpriv->free_xmitbuf_cnt); */ /* DBG_871X("!m2u); */ diff --git a/drivers/staging/rtlwifi/base.c b/drivers/staging/rtlwifi/base.c index c947def37d31..eea00035a735 100644 --- a/drivers/staging/rtlwifi/base.c +++ b/drivers/staging/rtlwifi/base.c @@ -710,20 +710,20 @@ u8 rtl_mrate_idx_to_arfr_id( ret = RATEID_IDX_BGN_40M_1SS; else ret = RATEID_IDX_BGN_40M_2SS; - ; break; + break; case RATR_INX_WIRELESS_N: case RATR_INX_WIRELESS_NG: if (rtlphy->rf_type == RF_1T1R) ret = RATEID_IDX_GN_N1SS; else ret = RATEID_IDX_GN_N2SS; - ; break; + break; case RATR_INX_WIRELESS_NB: if (rtlphy->rf_type == RF_1T1R) ret = RATEID_IDX_BGN_20M_1SS_BN; else ret = RATEID_IDX_BGN_20M_2SS_BN; - ; break; + break; case RATR_INX_WIRELESS_GB: ret = RATEID_IDX_BG; break; diff --git a/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c index ffff5b062672..5b826403ed66 100644 --- a/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c +++ b/drivers/staging/rtlwifi/btcoexist/halbtc8822b2ant.c @@ -2885,12 +2885,8 @@ static void halbtc8822b2ant_action_a2dp(struct btc_coexist *btcoexist) NORMAL_EXEC, 5); } else { - if (wifi_turbo) - halbtc8822b2ant_coex_table_with_type( - btcoexist, NORMAL_EXEC, 10); - else - halbtc8822b2ant_coex_table_with_type( - btcoexist, NORMAL_EXEC, 10); + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 10); halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 109); diff --git a/drivers/staging/rtlwifi/phydm/phydm_features.h b/drivers/staging/rtlwifi/phydm/phydm_features.h index 37f6f0cd7235..a12361c6a1a0 100644 --- a/drivers/staging/rtlwifi/phydm/phydm_features.h +++ b/drivers/staging/rtlwifi/phydm/phydm_features.h @@ -24,7 +24,7 @@ *****************************************************************************/ #ifndef __PHYDM_FEATURES_H__ -#define __PHYDM_FEATURES +#define __PHYDM_FEATURES_H__ /*phydm debyg report & tools*/ diff --git a/drivers/staging/rtlwifi/phydm/phydm_kfree.h b/drivers/staging/rtlwifi/phydm/phydm_kfree.h index 1ee60059afc1..fa1627e3662d 100644 --- a/drivers/staging/rtlwifi/phydm/phydm_kfree.h +++ b/drivers/staging/rtlwifi/phydm/phydm_kfree.h @@ -24,7 +24,7 @@ *****************************************************************************/ #ifndef __PHYDMKFREE_H__ -#define __PHYDKFREE_H__ +#define __PHYDMKFREE_H__ #define KFREE_VERSION "1.0" diff --git a/drivers/staging/rtlwifi/phydm/phydm_rainfo.c b/drivers/staging/rtlwifi/phydm/phydm_rainfo.c index 8c08c76d4eda..e10a91aeebee 100644 --- a/drivers/staging/rtlwifi/phydm/phydm_rainfo.c +++ b/drivers/staging/rtlwifi/phydm/phydm_rainfo.c @@ -142,7 +142,6 @@ void odm_c2h_ra_para_report_handler(void *dm_void, u8 *cmd_buf, u8 cmd_len) "SGI_support =", cmd_buf[7]); ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "%5s %d\n", "Rate_ID =", cmd_buf[8]); - ; } ODM_RT_TRACE(dm, ODM_FW_DEBUG_TRACE, "-------------------------------\n"); diff --git a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c index d320311213cc..e2c72af16150 100644 --- a/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c +++ b/drivers/staging/rtlwifi/phydm/rtl8822b/phydm_iqk_8822b.c @@ -1311,7 +1311,7 @@ static void _phy_iq_calibrate_8822b(struct phy_dm_struct *dm, bool reset) iqk_info->kcount = 0; ODM_RT_TRACE(dm, ODM_COMP_CALIBRATION, "[IQK]delay 50ms!!!\n"); ODM_delay_ms(50); - }; + } _iqk_backup_iqk_8822b(dm, 1); _iqk_fill_iqk_report_8822b(dm, 0); diff --git a/drivers/staging/rtlwifi/rtl8822be/phy.c b/drivers/staging/rtlwifi/rtl8822be/phy.c index ef37ae98c803..6697aee9317f 100644 --- a/drivers/staging/rtlwifi/rtl8822be/phy.c +++ b/drivers/staging/rtlwifi/rtl8822be/phy.c @@ -1251,7 +1251,7 @@ static void _rtl8822be_get_rate_values_of_tx_power_by_rate( RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Invalid reg_addr 0x%x in %s()\n", reg_addr, __func__); break; - }; + } } void rtl8822be_store_tx_power_by_rate(struct ieee80211_hw *hw, u32 band, diff --git a/drivers/staging/rtlwifi/wifi.h b/drivers/staging/rtlwifi/wifi.h index ca0243fa2e66..a23bb1719e35 100644 --- a/drivers/staging/rtlwifi/wifi.h +++ b/drivers/staging/rtlwifi/wifi.h @@ -2379,16 +2379,17 @@ struct rtl_hal_usbint_cfg { u32 rx_max_size; /* op - rx */ - void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *); - void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *, - struct sk_buff_head *); + void (*usb_rx_hdl)(struct ieee80211_hw *hw, struct sk_buff *skb); + void (*usb_rx_segregate_hdl)(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct sk_buff_head *skbh); /* tx */ - void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *); - int (*usb_tx_post_hdl)(struct ieee80211_hw *, struct urb *, - struct sk_buff *); - struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *, - struct sk_buff_head *); + void (*usb_tx_cleanup)(struct ieee80211_hw *hw, struct sk_buff *skb); + int (*usb_tx_post_hdl)(struct ieee80211_hw *hw, struct urb *urb, + struct sk_buff *skb); + struct sk_buff *(*usb_tx_aggregate_hdl)(struct ieee80211_hw *hw, + struct sk_buff_head *skbh); /* endpoint mapping */ int (*usb_endpoint_mapping)(struct ieee80211_hw *hw); @@ -2693,12 +2694,12 @@ struct rtl_btc_ops { }; struct rtl_halmac_ops { - int (*halmac_init_adapter)(struct rtl_priv *); - int (*halmac_deinit_adapter)(struct rtl_priv *); - int (*halmac_init_hal)(struct rtl_priv *); - int (*halmac_deinit_hal)(struct rtl_priv *); - int (*halmac_poweron)(struct rtl_priv *); - int (*halmac_poweroff)(struct rtl_priv *); + int (*halmac_init_adapter)(struct rtl_priv *rtlpriv); + int (*halmac_deinit_adapter)(struct rtl_priv *rtlpriv); + int (*halmac_init_hal)(struct rtl_priv *rtlpriv); + int (*halmac_deinit_hal)(struct rtl_priv *rtlpriv); + int (*halmac_poweron)(struct rtl_priv *rtlpriv); + int (*halmac_poweroff)(struct rtl_priv *rtlpriv); int (*halmac_phy_power_switch)(struct rtl_priv *rtlpriv, u8 enable); int (*halmac_set_mac_address)(struct rtl_priv *rtlpriv, u8 hwport, diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c index 313b99104398..4c1f00f551da 100644 --- a/drivers/staging/sm750fb/ddk750_chip.c +++ b/drivers/staging/sm750fb/ddk750_chip.c @@ -8,9 +8,9 @@ #define MHz(x) ((x) * 1000000) -static logical_chip_type_t chip; +static enum logical_chip_type chip; -logical_chip_type_t sm750_get_chip_type(void) +enum logical_chip_type sm750_get_chip_type(void) { return chip; } diff --git a/drivers/staging/sm750fb/ddk750_chip.h b/drivers/staging/sm750fb/ddk750_chip.h index aee82fcaf669..c72aac21b675 100644 --- a/drivers/staging/sm750fb/ddk750_chip.h +++ b/drivers/staging/sm750fb/ddk750_chip.h @@ -24,25 +24,23 @@ static inline void poke32(u32 addr, u32 data) } /* This is all the chips recognized by this library */ -typedef enum _logical_chip_type_t { +enum logical_chip_type { SM_UNKNOWN, SM718, SM750, SM750LE, -} -logical_chip_type_t; +}; -typedef enum _clock_type_t { +enum clock_type { MXCLK_PLL, PRIMARY_PLL, SECONDARY_PLL, VGA0_PLL, VGA1_PLL, -} -clock_type_t; +}; struct pll_value { - clock_type_t clockType; + enum clock_type clockType; unsigned long inputFreq; /* Input clock frequency to the PLL */ /* Use this when clockType = PANEL_PLL */ @@ -94,7 +92,7 @@ struct initchip_param { /* More initialization parameter can be added if needed */ }; -logical_chip_type_t sm750_get_chip_type(void); +enum logical_chip_type sm750_get_chip_type(void); void sm750_set_chip_type(unsigned short devId, u8 revId); unsigned int sm750_calc_pll_value(unsigned int request, struct pll_value *pll); unsigned int sm750_format_pll_reg(struct pll_value *pPLL); diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index c6fd90191530..1273e7d18925 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -111,7 +111,7 @@ static void swPanelPowerSequence(int disp, int delay) primary_wait_vertical_sync(delay); } -void ddk750_setLogicalDispOut(disp_output_t output) +void ddk750_setLogicalDispOut(enum disp_output output) { unsigned int reg; diff --git a/drivers/staging/sm750fb/ddk750_display.h b/drivers/staging/sm750fb/ddk750_display.h index 523bbf33521c..7fd101d98199 100644 --- a/drivers/staging/sm750fb/ddk750_display.h +++ b/drivers/staging/sm750fb/ddk750_display.h @@ -89,7 +89,7 @@ * LCD1 means panel path TFT1 & panel path DVI (so enable DAC) * CRT means crt path DSUB */ -typedef enum _disp_output_t { +enum disp_output { do_LCD1_PRI = PNL_2_PRI | PRI_TP_ON | PNL_SEQ_ON | DAC_ON, do_LCD1_SEC = PNL_2_SEC | SEC_TP_ON | PNL_SEQ_ON | DAC_ON, do_LCD2_PRI = CRT_2_PRI | PRI_TP_ON | DUAL_TFT_ON, @@ -100,9 +100,8 @@ typedef enum _disp_output_t { */ do_CRT_PRI = CRT_2_PRI | PRI_TP_ON | DPMS_ON | DAC_ON, do_CRT_SEC = CRT_2_SEC | SEC_TP_ON | DPMS_ON | DAC_ON, -} -disp_output_t; +}; -void ddk750_setLogicalDispOut(disp_output_t output); +void ddk750_setLogicalDispOut(enum disp_output output); #endif diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 2cdd87b78e58..7e22d093b091 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -206,7 +206,7 @@ static int programModeRegisters(struct mode_parameter *pModeParam, return ret; } -int ddk750_setModeTiming(struct mode_parameter *parm, clock_type_t clock) +int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock) { struct pll_value pll; unsigned int uiActualPixelClk; diff --git a/drivers/staging/sm750fb/ddk750_mode.h b/drivers/staging/sm750fb/ddk750_mode.h index 259a9d6a4eb2..2df78a0937b2 100644 --- a/drivers/staging/sm750fb/ddk750_mode.h +++ b/drivers/staging/sm750fb/ddk750_mode.h @@ -33,5 +33,5 @@ struct mode_parameter { enum spolarity clock_phase_polarity; }; -int ddk750_setModeTiming(struct mode_parameter *parm, clock_type_t clock); +int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock); #endif diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index a8c79864ee4b..edeae9d06883 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -185,7 +185,7 @@ int hw_sm750_output_setMode(struct lynxfb_output *output, struct fb_fix_screeninfo *fix) { int ret; - disp_output_t disp_set; + enum disp_output disp_set; int channel; ret = 0; @@ -254,7 +254,7 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, int ret, fmt; u32 reg; struct mode_parameter modparm; - clock_type_t clock; + enum clock_type clock; struct sm750_dev *sm750_dev; struct lynxfb_par *par; diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index cf1259059776..af30b7099bed 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -417,7 +417,7 @@ static void announce_edge(struct vc_data *vc, int msg_id) bleep(spk_y); if ((spk_bleeps & 2) && (msg_id < edge_quiet)) synth_printf("%s\n", - spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1)); + spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1)); } static void speak_char(u16 ch) @@ -449,8 +449,9 @@ static void speak_char(u16 ch) if (*cp == '^') { cp++; synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp); - } else + } else { synth_printf(" %s ", cp); + } } } @@ -561,7 +562,7 @@ static u_long get_word(struct vc_data *vc) get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) { tmp_pos += 2; tmpx++; - } else + } else { while (tmpx > 0) { ch = get_char(vc, (u_short *)tmp_pos - 1, &temp); if ((ch == SPACE || ch == 0 || @@ -571,6 +572,7 @@ static u_long get_word(struct vc_data *vc) tmp_pos -= 2; tmpx--; } + } attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr); buf[cnt++] = attr_ch; while (tmpx < vc->vc_cols - 1) { diff --git a/drivers/staging/speakup/speakup_decpc.c b/drivers/staging/speakup/speakup_decpc.c index 303f393d3f2f..6649309e0342 100644 --- a/drivers/staging/speakup/speakup_decpc.c +++ b/drivers/staging/speakup/speakup_decpc.c @@ -349,7 +349,7 @@ static int testkernel(void) return 0; else if (dt_stat == 0x0dec) pr_warn("dec_pc at 0x%x, software not loaded\n", - speakup_info.port_tts); + speakup_info.port_tts); status = -3; oops: synth_release_region(speakup_info.port_tts, SYNTH_IO_EXTENT); speakup_info.port_tts = 0; @@ -412,11 +412,11 @@ static void do_catch_up(struct spk_synth *synth) if (!in_escape) dt_sendchar(PROCSPEECH); spin_lock_irqsave(&speakup_info.spinlock, - flags); + flags); jiffy_delta_val = jiffy_delta->u.n.value; delay_time_val = delay_time->u.n.value; spin_unlock_irqrestore(&speakup_info.spinlock, - flags); + flags); schedule_timeout(msecs_to_jiffies (delay_time_val)); jiff_max = jiffies + jiffy_delta_val; diff --git a/drivers/staging/speakup/speakup_dectlk.c b/drivers/staging/speakup/speakup_dectlk.c index 2ea22a2eb5f9..a144f28ee1a8 100644 --- a/drivers/staging/speakup/speakup_dectlk.c +++ b/drivers/staging/speakup/speakup_dectlk.c @@ -262,11 +262,11 @@ static void do_catch_up(struct spk_synth *synth) if (!in_escape) synth->io_ops->synth_out(synth, PROCSPEECH); spin_lock_irqsave(&speakup_info.spinlock, - flags); + flags); jiffy_delta_val = jiffy_delta->u.n.value; delay_time_val = delay_time->u.n.value; spin_unlock_irqrestore(&speakup_info.spinlock, - flags); + flags); schedule_timeout(msecs_to_jiffies (delay_time_val)); jiff_max = jiffies + jiffy_delta_val; diff --git a/drivers/staging/speakup/speakup_dtlk.c b/drivers/staging/speakup/speakup_dtlk.c index f8cb83c9b82e..dbebed0eeeec 100644 --- a/drivers/staging/speakup/speakup_dtlk.c +++ b/drivers/staging/speakup/speakup_dtlk.c @@ -266,7 +266,7 @@ static char synth_read_tts(void) outb_p(ch, speakup_info.port_tts); while (synth_readable()) cpu_relax(); - return (char) ch; + return (char)ch; } /* interrogate the DoubleTalk PC and return its settings */ @@ -287,7 +287,7 @@ static struct synth_settings *synth_interrogate(struct spk_synth *synth) } t = buf; /* serial number is little endian */ - status.serial_number = t[0] + t[1]*256; + status.serial_number = t[0] + t[1] * 256; t += 2; for (i = 0; *t != '\r'; t++) { status.rom_version[i] = *t; @@ -323,29 +323,29 @@ static int synth_probe(struct spk_synth *synth) if (port_forced) { speakup_info.port_tts = port_forced; pr_info("probe forced to %x by kernel command line\n", - speakup_info.port_tts); + speakup_info.port_tts); if ((port_forced & 0xf) != 0xf) pr_info("warning: port base should probably end with f\n"); - if (synth_request_region(speakup_info.port_tts-1, - SYNTH_IO_EXTENT)) { + if (synth_request_region(speakup_info.port_tts - 1, + SYNTH_IO_EXTENT)) { pr_warn("sorry, port already reserved\n"); return -EBUSY; } - port_val = inw(speakup_info.port_tts-1); - synth_lpc = speakup_info.port_tts-1; + port_val = inw(speakup_info.port_tts - 1); + synth_lpc = speakup_info.port_tts - 1; } else { for (i = 0; synth_portlist[i]; i++) { if (synth_request_region(synth_portlist[i], - SYNTH_IO_EXTENT)) + SYNTH_IO_EXTENT)) continue; port_val = inw(synth_portlist[i]) & 0xfbff; if (port_val == 0x107f) { synth_lpc = synth_portlist[i]; - speakup_info.port_tts = synth_lpc+1; + speakup_info.port_tts = synth_lpc + 1; break; } synth_release_region(synth_portlist[i], - SYNTH_IO_EXTENT); + SYNTH_IO_EXTENT); } } port_val &= 0xfbff; @@ -359,7 +359,7 @@ static int synth_probe(struct spk_synth *synth) cpu_relax(); /* wait until it's ready */ sp = synth_interrogate(synth); pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n", - synth->long_name, synth_lpc, synth_lpc+SYNTH_IO_EXTENT - 1, + synth->long_name, synth_lpc, synth_lpc + SYNTH_IO_EXTENT - 1, sp->rom_version, sp->serial_number, synth->version); synth->alive = 1; return 0; @@ -369,7 +369,8 @@ static void dtlk_release(void) { spk_stop_serial_interrupt(); if (speakup_info.port_tts) - synth_release_region(speakup_info.port_tts-1, SYNTH_IO_EXTENT); + synth_release_region(speakup_info.port_tts - 1, + SYNTH_IO_EXTENT); speakup_info.port_tts = 0; } diff --git a/drivers/staging/speakup/speakup_dummy.c b/drivers/staging/speakup/speakup_dummy.c index a30d60450bd5..aa0c900f79f2 100644 --- a/drivers/staging/speakup/speakup_dummy.c +++ b/drivers/staging/speakup/speakup_dummy.c @@ -94,7 +94,7 @@ static struct spk_synth synth_dummy = { .probe = spk_ttyio_synth_probe, .release = spk_ttyio_release, .synth_immediate = spk_ttyio_synth_immediate, - .catch_up = spk_do_catch_up, + .catch_up = spk_do_catch_up_unicode, .flush = spk_synth_flush, .is_alive = spk_synth_is_alive_restart, .synth_adjust = NULL, diff --git a/drivers/staging/speakup/speakup_keypc.c b/drivers/staging/speakup/speakup_keypc.c index de76183932e1..3901734982a4 100644 --- a/drivers/staging/speakup/speakup_keypc.c +++ b/drivers/staging/speakup/speakup_keypc.c @@ -260,7 +260,7 @@ static int synth_probe(struct spk_synth *synth) if (port_forced) { synth_port = port_forced; pr_info("probe forced to %x by kernel command line\n", - synth_port); + synth_port); if (synth_request_region(synth_port-1, SYNTH_IO_EXTENT)) { pr_warn("sorry, port already reserved\n"); return -EBUSY; @@ -269,7 +269,7 @@ static int synth_probe(struct spk_synth *synth) } else { for (i = 0; synth_portlist[i]; i++) { if (synth_request_region(synth_portlist[i], - SYNTH_IO_EXTENT)) { + SYNTH_IO_EXTENT)) { pr_warn ("request_region: failed with 0x%x, %d\n", synth_portlist[i], SYNTH_IO_EXTENT); diff --git a/drivers/staging/speakup/spk_priv.h b/drivers/staging/speakup/spk_priv.h index 00430437eb4c..7b3a16e1fa23 100644 --- a/drivers/staging/speakup/spk_priv.h +++ b/drivers/staging/speakup/spk_priv.h @@ -57,6 +57,7 @@ int spk_ttyio_synth_probe(struct spk_synth *synth); const char *spk_serial_synth_immediate(struct spk_synth *synth, const char *buff); const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff); void spk_do_catch_up(struct spk_synth *synth); +void spk_do_catch_up_unicode(struct spk_synth *synth); void spk_synth_flush(struct spk_synth *synth); unsigned char spk_synth_get_index(struct spk_synth *synth); int spk_synth_is_alive_nop(struct spk_synth *synth); diff --git a/drivers/staging/speakup/spk_ttyio.c b/drivers/staging/speakup/spk_ttyio.c index 5aa3ffa3772d..eac63aab8162 100644 --- a/drivers/staging/speakup/spk_ttyio.c +++ b/drivers/staging/speakup/spk_ttyio.c @@ -71,7 +71,7 @@ static void spk_ttyio_ldisc_close(struct tty_struct *tty) } static int spk_ttyio_receive_buf2(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) + const unsigned char *cp, char *fp, int count) { struct spk_ldisc_data *ldisc_data = tty->disc_data; @@ -110,6 +110,7 @@ static struct tty_ldisc_ops spk_ttyio_ldisc_ops = { }; static int spk_ttyio_out(struct spk_synth *in_synth, const char ch); +static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch); static void spk_ttyio_send_xchar(char ch); static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear); static unsigned char spk_ttyio_in(void); @@ -118,6 +119,7 @@ static void spk_ttyio_flush_buffer(void); struct spk_io_ops spk_ttyio_ops = { .synth_out = spk_ttyio_out, + .synth_out_unicode = spk_ttyio_out_unicode, .send_xchar = spk_ttyio_send_xchar, .tiocmset = spk_ttyio_tiocmset, .synth_in = spk_ttyio_in, @@ -221,6 +223,23 @@ static int spk_ttyio_out(struct spk_synth *in_synth, const char ch) return 0; } +static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch) +{ + int ret; + + if (ch < 0x80) + ret = spk_ttyio_out(in_synth, ch); + else if (ch < 0x800) { + ret = spk_ttyio_out(in_synth, 0xc0 | (ch >> 6)); + ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f)); + } else { + ret = spk_ttyio_out(in_synth, 0xe0 | (ch >> 12)); + ret &= spk_ttyio_out(in_synth, 0x80 | ((ch >> 6) & 0x3f)); + ret &= spk_ttyio_out(in_synth, 0x80 | (ch & 0x3f)); + } + return ret; +} + static int check_tty(struct tty_struct *tty) { if (!tty) { diff --git a/drivers/staging/speakup/spk_types.h b/drivers/staging/speakup/spk_types.h index c50de6035a9a..4203bed90b4f 100644 --- a/drivers/staging/speakup/spk_types.h +++ b/drivers/staging/speakup/spk_types.h @@ -151,6 +151,7 @@ struct spk_synth; struct spk_io_ops { int (*synth_out)(struct spk_synth *synth, const char ch); + int (*synth_out_unicode)(struct spk_synth *synth, u16 ch); void (*send_xchar)(char ch); void (*tiocmset)(unsigned int set, unsigned int clear); unsigned char (*synth_in)(void); diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c index c06e6a810999..7deeb7061018 100644 --- a/drivers/staging/speakup/synth.c +++ b/drivers/staging/speakup/synth.c @@ -52,9 +52,9 @@ static int do_synth_init(struct spk_synth *in_synth); * For devices that have a "full" notification mechanism, the driver can * adapt the loop the way they prefer. */ -void spk_do_catch_up(struct spk_synth *synth) +static void _spk_do_catch_up(struct spk_synth *synth, int unicode) { - u_char ch; + u16 ch; unsigned long flags; unsigned long jiff_max; struct var_t *delay_time; @@ -63,6 +63,7 @@ void spk_do_catch_up(struct spk_synth *synth) int jiffy_delta_val; int delay_time_val; int full_time_val; + int ret; jiffy_delta = spk_get_var(JIFFY); full_time = spk_get_var(FULL); @@ -81,7 +82,8 @@ void spk_do_catch_up(struct spk_synth *synth) synth->flush(synth); continue; } - synth_buffer_skip_nonlatin1(); + if (!unicode) + synth_buffer_skip_nonlatin1(); if (synth_buffer_empty()) { spin_unlock_irqrestore(&speakup_info.spinlock, flags); break; @@ -92,7 +94,11 @@ void spk_do_catch_up(struct spk_synth *synth) spin_unlock_irqrestore(&speakup_info.spinlock, flags); if (ch == '\n') ch = synth->procspeech; - if (!synth->io_ops->synth_out(synth, ch)) { + if (unicode) + ret = synth->io_ops->synth_out_unicode(synth, ch); + else + ret = synth->io_ops->synth_out(synth, ch); + if (!ret) { schedule_timeout(msecs_to_jiffies(full_time_val)); continue; } @@ -117,8 +123,19 @@ void spk_do_catch_up(struct spk_synth *synth) } synth->io_ops->synth_out(synth, synth->procspeech); } + +void spk_do_catch_up(struct spk_synth *synth) +{ + _spk_do_catch_up(synth, 0); +} EXPORT_SYMBOL_GPL(spk_do_catch_up); +void spk_do_catch_up_unicode(struct spk_synth *synth) +{ + _spk_do_catch_up(synth, 1); +} +EXPORT_SYMBOL_GPL(spk_do_catch_up_unicode); + void spk_synth_flush(struct spk_synth *synth) { synth->io_ops->flush_buffer(); diff --git a/drivers/staging/unisys/visorinput/Kconfig b/drivers/staging/unisys/visorinput/Kconfig index 655cd62433de..a3817e0f7e5c 100644 --- a/drivers/staging/unisys/visorinput/Kconfig +++ b/drivers/staging/unisys/visorinput/Kconfig @@ -4,7 +4,7 @@ config UNISYS_VISORINPUT tristate "Unisys visorinput driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && FB && INPUT + depends on UNISYSSPAR && UNISYS_VISORBUS && INPUT ---help--- The Unisys s-Par visorinput driver provides a virtualized system console (keyboard and mouse) that is accessible through the diff --git a/drivers/staging/unisys/visorinput/Makefile b/drivers/staging/unisys/visorinput/Makefile index beedca7f0e09..6e4bfa059a1f 100644 --- a/drivers/staging/unisys/visorinput/Makefile +++ b/drivers/staging/unisys/visorinput/Makefile @@ -4,4 +4,3 @@ obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput.o -ccflags-y += -Idrivers/staging/unisys/include diff --git a/drivers/staging/unisys/visorinput/ultrainputreport.h b/drivers/staging/unisys/visorinput/ultrainputreport.h deleted file mode 100644 index 67dac430ce0c..000000000000 --- a/drivers/staging/unisys/visorinput/ultrainputreport.h +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - */ - -#ifndef __SPAR_ULTRAINPUTREPORT_H__ -#define __SPAR_ULTRAINPUTREPORT_H__ - -#include <linux/types.h> - -/* These defines identify mouse and keyboard activity which is specified by the - * firmware to the host using the cmsimpleinput protocol. @ingroup coretypes - */ - /* only motion; arg1=x, arg2=y */ -#define INPUTACTION_XY_MOTION 1 -/* arg1: 1=left,2=center,3=right */ -#define INPUTACTION_MOUSE_BUTTON_DOWN 2 -/* arg1: 1=left,2=center,3=right */ -#define INPUTACTION_MOUSE_BUTTON_UP 3 -/* arg1: 1=left,2=center,3=right */ -#define INPUTACTION_MOUSE_BUTTON_CLICK 4 -/* arg1: 1=left,2=center 3=right */ -#define INPUTACTION_MOUSE_BUTTON_DCLICK 5 -/* arg1: wheel rotation away from user */ -#define INPUTACTION_WHEEL_ROTATE_AWAY 6 -/* arg1: wheel rotation toward user */ -#define INPUTACTION_WHEEL_ROTATE_TOWARD 7 -/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1 - * is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st - * byte in the low 8 bits, and the 2nd byte in the high 8 bits. - * E.g., the right ALT key would appear as x'38e0'. - */ -#define INPUTACTION_KEY_DOWN 64 -/* arg1: scancode (in same format as inputaction_keyDown) */ -#define INPUTACTION_KEY_UP 65 -/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of - * the locking keys, like capslock, numlock, or scrolllock. - * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON) - */ -#define INPUTACTION_SET_LOCKING_KEY_STATE 66 -/* arg1: scancode (in same format as inputaction_keyDown */ -#define INPUTACTION_KEY_DOWN_UP 67 - -struct visor_inputactivity { - u16 action; - u16 arg1; - u16 arg2; - u16 arg3; -} __packed; - -struct visor_inputreport { - u64 seq_no; - struct visor_inputactivity activity; -} __packed; - -#endif diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c index d8048e48658f..9693fb559052 100644 --- a/drivers/staging/unisys/visorinput/visorinput.c +++ b/drivers/staging/unisys/visorinput/visorinput.c @@ -18,7 +18,36 @@ #include <linux/uuid.h> #include <linux/visorbus.h> -#include "ultrainputreport.h" +/* These defines identify mouse and keyboard activity which is specified by the + * firmware to the host using the cmsimpleinput protocol. @ingroup coretypes + */ +/* only motion; arg1=x, arg2=y */ +#define INPUTACTION_XY_MOTION 1 + +/* arg1: 1=left,2=center,3=right */ +#define INPUTACTION_MOUSE_BUTTON_DOWN 2 +#define INPUTACTION_MOUSE_BUTTON_UP 3 +#define INPUTACTION_MOUSE_BUTTON_CLICK 4 +#define INPUTACTION_MOUSE_BUTTON_DCLICK 5 + +/* arg1: wheel rotation away from/toward user */ +#define INPUTACTION_WHEEL_ROTATE_AWAY 6 +#define INPUTACTION_WHEEL_ROTATE_TOWARD 7 + +/* arg1: scancode, as follows: If arg1 <= 0xff, it's a 1-byte scancode and arg1 + * is that scancode. If arg1 > 0xff, it's a 2-byte scanecode, with the 1st + * byte in the low 8 bits, and the 2nd byte in the high 8 bits. + * E.g., the right ALT key would appear as x'38e0'. + */ +#define INPUTACTION_KEY_DOWN 64 +#define INPUTACTION_KEY_UP 65 +#define INPUTACTION_KEY_DOWN_UP 67 + +/* arg1: scancode (in same format as inputaction_keyDown); MUST refer to one of + * the locking keys, like capslock, numlock, or scrolllock. + * arg2: 1 iff locking key should be in the LOCKED position (e.g., light is ON) + */ +#define INPUTACTION_SET_LOCKING_KEY_STATE 66 /* Keyboard channel {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */ #define VISOR_KEYBOARD_CHANNEL_GUID \ @@ -32,19 +61,45 @@ 0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87) #define VISOR_MOUSE_CHANNEL_GUID_STR "addf07d4-94a9-46e2-81c3-61abcdbdbd87" -#define PIXELS_ACROSS_DEFAULT 800 -#define PIXELS_DOWN_DEFAULT 600 +#define PIXELS_ACROSS_DEFAULT 1024 +#define PIXELS_DOWN_DEFAULT 768 #define KEYCODE_TABLE_BYTES 256 -enum visorinput_device_type { +struct visor_inputactivity { + u16 action; + u16 arg1; + u16 arg2; + u16 arg3; +} __packed; + +struct visor_inputreport { + u64 seq_no; + struct visor_inputactivity activity; +} __packed; + +/* header of keyboard/mouse channels */ +struct visor_input_channel_data { + u32 n_input_reports; + union { + struct { + u16 x_res; + u16 y_res; + } mouse; + struct { + u32 flags; + } keyboard; + }; +} __packed; + +enum visorinput_dev_type { visorinput_keyboard, visorinput_mouse, }; /* - * This is the private data that we store for each device. - * A pointer to this struct is maintained via - * dev_get_drvdata() / dev_set_drvdata() for each struct device. + * This is the private data that we store for each device. A pointer to this + * struct is maintained via dev_get_drvdata() / dev_set_drvdata() for each + * struct device. */ struct visorinput_devdata { struct visor_device *dev; @@ -215,10 +270,9 @@ static int visorinput_open(struct input_dev *visorinput_dev) dev_dbg(&visorinput_dev->dev, "%s opened\n", __func__); /* - * If we're not paused, really enable interrupts. - * Regardless of whether we are paused, set a flag indicating - * interrupts should be enabled so when we resume, interrupts - * will really be enabled. + * If we're not paused, really enable interrupts. Regardless of whether + * we are paused, set a flag indicating interrupts should be enabled so + * when we resume, interrupts will really be enabled. */ mutex_lock(&devdata->lock_visor_dev); devdata->interrupts_enabled = true; @@ -244,10 +298,9 @@ static void visorinput_close(struct input_dev *visorinput_dev) dev_dbg(&visorinput_dev->dev, "%s closed\n", __func__); /* - * If we're not paused, really disable interrupts. - * Regardless of whether we are paused, set a flag indicating - * interrupts should be disabled so when we resume we will - * not re-enable them. + * If we're not paused, really disable interrupts. Regardless of + * whether we are paused, set a flag indicating interrupts should be + * disabled so when we resume we will not re-enable them. */ mutex_lock(&devdata->lock_visor_dev); devdata->interrupts_enabled = false; @@ -260,9 +313,9 @@ out_unlock: } /* - * setup_client_keyboard() initializes and returns a Linux input node that - * we can use to deliver keyboard inputs to Linux. We of course do this when - * we see keyboard inputs coming in on a keyboard channel. + * setup_client_keyboard() initializes and returns a Linux input node that we + * can use to deliver keyboard inputs to Linux. We of course do this when we + * see keyboard inputs coming in on a keyboard channel. */ static struct input_dev *setup_client_keyboard(void *devdata, unsigned char *keycode_table) @@ -306,10 +359,9 @@ static struct input_dev *setup_client_keyboard(void *devdata, return visorinput_dev; } -static struct input_dev *setup_client_mouse(void *devdata) +static struct input_dev *setup_client_mouse(void *devdata, unsigned int xres, + unsigned int yres) { - int xres, yres; - struct fb_info *fb0; struct input_dev *visorinput_dev = input_allocate_device(); if (!visorinput_dev) @@ -327,14 +379,10 @@ static struct input_dev *setup_client_mouse(void *devdata) set_bit(BTN_RIGHT, visorinput_dev->keybit); set_bit(BTN_MIDDLE, visorinput_dev->keybit); - if (registered_fb[0]) { - fb0 = registered_fb[0]; - xres = fb0->var.xres_virtual; - yres = fb0->var.yres_virtual; - } else { + if (xres == 0) xres = PIXELS_ACROSS_DEFAULT; + if (yres == 0) yres = PIXELS_DOWN_DEFAULT; - } input_set_abs_params(visorinput_dev, ABS_X, 0, xres, 0, 0); input_set_abs_params(visorinput_dev, ABS_Y, 0, yres, 0, 0); @@ -347,14 +395,15 @@ static struct input_dev *setup_client_mouse(void *devdata) return visorinput_dev; } -static struct visorinput_devdata *devdata_create( - struct visor_device *dev, - enum visorinput_device_type devtype) +static struct visorinput_devdata *devdata_create(struct visor_device *dev, + enum visorinput_dev_type dtype) { struct visorinput_devdata *devdata = NULL; unsigned int extra_bytes = 0; + unsigned int size, xres, yres, err; + struct visor_input_channel_data data; - if (devtype == visorinput_keyboard) + if (dtype == visorinput_keyboard) /* allocate room for devdata->keycode_table, filled in below */ extra_bytes = KEYCODE_TABLE_BYTES * 2; devdata = kzalloc(sizeof(*devdata) + extra_bytes, GFP_KERNEL); @@ -373,11 +422,11 @@ static struct visorinput_devdata *devdata_create( devdata->paused = true; /* - * This is an input device in a client guest partition, - * so we need to create whatever input nodes are necessary to - * deliver our inputs to the guest OS. + * This is an input device in a client guest partition, so we need to + * create whatever input nodes are necessary to deliver our inputs to + * the guest OS. */ - switch (devtype) { + switch (dtype) { case visorinput_keyboard: devdata->keycode_table_bytes = extra_bytes; memcpy(devdata->keycode_table, visorkbd_keycode, @@ -390,7 +439,15 @@ static struct visorinput_devdata *devdata_create( goto cleanups_register; break; case visorinput_mouse: - devdata->visorinput_dev = setup_client_mouse(devdata); + size = sizeof(struct visor_input_channel_data); + err = visorbus_read_channel(dev, sizeof(struct channel_header), + &data, size); + if (err) + goto cleanups_register; + xres = data.mouse.x_res; + yres = data.mouse.y_res; + devdata->visorinput_dev = setup_client_mouse(devdata, xres, + yres); if (!devdata->visorinput_dev) goto cleanups_register; break; @@ -404,10 +461,9 @@ static struct visorinput_devdata *devdata_create( /* * Device struct is completely set up now, with the exception of - * visorinput_dev being registered. - * We need to unlock before we register the device, because this - * can cause an on-stack call of visorinput_open(), which would - * deadlock if we had the lock. + * visorinput_dev being registered. We need to unlock before we + * register the device, because this can cause an on-stack call of + * visorinput_open(), which would deadlock if we had the lock. */ if (input_register_device(devdata->visorinput_dev)) { input_free_device(devdata->visorinput_dev); @@ -416,9 +472,9 @@ static struct visorinput_devdata *devdata_create( mutex_lock(&devdata->lock_visor_dev); /* - * Establish calls to visorinput_channel_interrupt() if that is - * the desired state that we've kept track of in interrupts_enabled - * while the device was being created. + * Establish calls to visorinput_channel_interrupt() if that is the + * desired state that we've kept track of in interrupts_enabled while + * the device was being created. */ devdata->paused = false; if (devdata->interrupts_enabled) @@ -437,17 +493,17 @@ err_kfree_devdata: static int visorinput_probe(struct visor_device *dev) { const guid_t *guid; - enum visorinput_device_type devtype; + enum visorinput_dev_type dtype; guid = visorchannel_get_guid(dev->visorchannel); if (guid_equal(guid, &visor_mouse_channel_guid)) - devtype = visorinput_mouse; + dtype = visorinput_mouse; else if (guid_equal(guid, &visor_keyboard_channel_guid)) - devtype = visorinput_keyboard; + dtype = visorinput_keyboard; else return -ENODEV; visorbus_disable_channel_interrupts(dev); - if (!devdata_create(dev, devtype)) + if (!devdata_create(dev, dtype)) return -ENOMEM; return 0; } @@ -469,8 +525,8 @@ static void visorinput_remove(struct visor_device *dev) visorbus_disable_channel_interrupts(dev); /* - * due to above, at this time no thread of execution will be - * in visorinput_channel_interrupt() + * due to above, at this time no thread of execution will be in + * visorinput_channel_interrupt() */ dev_set_drvdata(&dev->device, NULL); @@ -513,9 +569,8 @@ static void handle_locking_key(struct input_dev *visorinput_dev, int keycode, } /* - * <scancode> is either a 1-byte scancode, or an extended 16-bit scancode - * with 0xE0 in the low byte and the extended scancode value in the next - * higher byte. + * <scancode> is either a 1-byte scancode, or an extended 16-bit scancode with + * 0xE0 in the low byte and the extended scancode value in the next higher byte. */ static int scancode_to_keycode(int scancode) { @@ -656,8 +711,8 @@ static int visorinput_pause(struct visor_device *dev, visorbus_disable_channel_interrupts(dev); /* - * due to above, at this time no thread of execution will be - * in visorinput_channel_interrupt() + * due to above, at this time no thread of execution will be in + * visorinput_channel_interrupt() */ devdata->paused = true; complete_func(dev, 0); @@ -687,9 +742,9 @@ static int visorinput_resume(struct visor_device *dev, complete_func(dev, 0); /* - * Re-establish calls to visorinput_channel_interrupt() if that is - * the desired state that we've kept track of in interrupts_enabled - * while the device was paused. + * Re-establish calls to visorinput_channel_interrupt() if that is the + * desired state that we've kept track of in interrupts_enabled while + * the device was paused. */ if (devdata->interrupts_enabled) visorbus_enable_channel_interrupts(dev); diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile index 1ecb261e04ae..fb26b826e640 100644 --- a/drivers/staging/vc04_services/Makefile +++ b/drivers/staging/vc04_services/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_BCM2835_VCHIQ) += vchiq.o vchiq-objs := \ interface/vchiq_arm/vchiq_core.o \ interface/vchiq_arm/vchiq_arm.o \ - interface/vchiq_arm/vchiq_kern_lib.o \ interface/vchiq_arm/vchiq_2835_arm.o \ interface/vchiq_arm/vchiq_debugfs.o \ interface/vchiq_arm/vchiq_shim.o \ diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c index 5f7551fbf5cf..8359cf881bef 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c @@ -209,6 +209,7 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) */ if (alsa_stream->running) { int err; + err = bcm2835_audio_stop(alsa_stream); alsa_stream->running = 0; if (err) @@ -278,7 +279,8 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) /* notify the vchiq that it should enter spdif passthrough mode by * setting channels=0 (see - * https://github.com/raspberrypi/linux/issues/528) */ + * https://github.com/raspberrypi/linux/issues/528) + */ if (chip->spdif_status & IEC958_AES0_NONAUDIO) channels = 0; else @@ -412,7 +414,7 @@ static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, int ret = snd_pcm_lib_ioctl(substream, cmd, arg); audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream, - cmd, arg, arg ? *(unsigned *) arg : 0, ret); + cmd, arg, arg ? *(unsigned int *)arg : 0, ret); return ret; } diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c index 045d577fe4f8..0ed21dd08170 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c @@ -25,6 +25,10 @@ MODULE_PARM_DESC(enable_compat_alsa, static void snd_devm_unregister_child(struct device *dev, void *res) { struct device *childdev = *(struct device **)res; + struct bcm2835_chip *chip = dev_get_drvdata(childdev); + struct snd_card *card = chip->card; + + snd_card_free(card); device_unregister(childdev); } @@ -50,6 +54,13 @@ static int snd_devm_add_child(struct device *dev, struct device *child) return 0; } +static void snd_bcm2835_release(struct device *dev) +{ + struct bcm2835_chip *chip = dev_get_drvdata(dev); + + kfree(chip); +} + static struct device * snd_create_device(struct device *parent, struct device_driver *driver, @@ -65,6 +76,7 @@ snd_create_device(struct device *parent, device_initialize(device); device->parent = parent; device->driver = driver; + device->release = snd_bcm2835_release; dev_set_name(device, "%s", name); @@ -75,18 +87,19 @@ snd_create_device(struct device *parent, return device; } -static int snd_bcm2835_free(struct bcm2835_chip *chip) -{ - kfree(chip); - return 0; -} - /* component-destructor * (see "Management of Cards and Components") */ static int snd_bcm2835_dev_free(struct snd_device *device) { - return snd_bcm2835_free(device->device_data); + struct bcm2835_chip *chip = device->device_data; + struct snd_card *card = chip->card; + + /* TODO: free pcm, ctl */ + + snd_device_free(card, chip); + + return 0; } /* chip-specific constructor @@ -111,7 +124,7 @@ static int snd_bcm2835_create(struct snd_card *card, err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err) { - snd_bcm2835_free(chip); + kfree(chip); return err; } @@ -119,31 +132,14 @@ static int snd_bcm2835_create(struct snd_card *card, return 0; } -static void snd_devm_card_free(struct device *dev, void *res) +static struct snd_card *snd_bcm2835_card_new(struct device *dev) { - struct snd_card *snd_card = *(struct snd_card **)res; - - snd_card_free(snd_card); -} - -static struct snd_card *snd_devm_card_new(struct device *dev) -{ - struct snd_card **dr; struct snd_card *card; int ret; - dr = devres_alloc(snd_devm_card_free, sizeof(*dr), GFP_KERNEL); - if (!dr) - return ERR_PTR(-ENOMEM); - ret = snd_card_new(dev, -1, NULL, THIS_MODULE, 0, &card); - if (ret) { - devres_free(dr); + if (ret) return ERR_PTR(ret); - } - - *dr = card; - devres_add(dev, dr); return card; } @@ -260,7 +256,7 @@ static int snd_add_child_device(struct device *device, return PTR_ERR(child); } - card = snd_devm_card_new(child); + card = snd_bcm2835_card_new(child); if (IS_ERR(card)) { dev_err(child, "Failed to create card"); return PTR_ERR(card); @@ -302,7 +298,7 @@ static int snd_add_child_device(struct device *device, return err; } - dev_set_drvdata(child, card); + dev_set_drvdata(child, chip); dev_info(child, "card created with %d channels\n", numchans); return 0; diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c index 0736214e1422..cff7b1e07153 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/controls.c +++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c @@ -1270,6 +1270,7 @@ int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev, * mismatches. */ int i; + mask = 1 << V4L2_SCENE_MODE_NONE; for (i = 0; i < ARRAY_SIZE(scene_configs); diff --git a/drivers/staging/vc04_services/interface/vchi/TODO b/drivers/staging/vc04_services/interface/vchi/TODO index df93154b1aa6..86708c7c8ec3 100644 --- a/drivers/staging/vc04_services/interface/vchi/TODO +++ b/drivers/staging/vc04_services/interface/vchi/TODO @@ -1,9 +1,4 @@ -1) Write a DT binding doc and get the corresponding DT node merged to - bcm2835. - -This will let the driver probe when enabled. - -2) Import drivers using VCHI. +1) Import drivers using VCHI. VCHI is just a tool to let drivers talk to the firmware. Here are some of the ones we want: @@ -14,11 +9,6 @@ some of the ones we want: requests to the firmware, which are transmitted across VCHIQ. vcdbg is really useful for debugging firmware interactions. - - bcm2835-camera (https://github.com/raspberrypi/linux/tree/rpi-4.4.y/drivers/media/platform/bcm2835) - - This driver will let us get images from the camera using the MMAL - protocol over VCHI. - - VCSM (https://github.com/raspberrypi/linux/tree/rpi-4.4.y/drivers/char/broadcom/vc_sm) This driver is used for talking about regions of VC memory across @@ -26,10 +16,41 @@ some of the ones we want: to manage these buffers as dmabufs so that we can zero-copy import camera images into vc4 for rendering/display. -3) Garbage-collect unused code +2) Garbage-collect unused code One of the reasons this driver wasn't upstreamed previously was that there's a lot code that got built that's probably unnecessary these days. Once we have the set of VCHI-using drivers we want in tree, we should be able to do a sweep of the code to see what's left that's unused. + +3) Make driver more portable + +Building this driver with arm/multi_v7_defconfig or arm64/defconfig +leads to data corruption during the following command: + + vchiq_test -f 1 + +This should be fixed. + +4) Fix kernel module support + +Even the VPU firmware doesn't support a VCHI re-connect, the driver +should properly handle a module unload. This also includes that all +resouces must be freed (kthreads, debugfs entries, ...) and global +variables avoided. + +5) Fix stack hog + +Running make checkstack shows that vchiq_dump_service_use_state() has +an extensive stack usage. Maybe other functions are also affected. + +6) Cleanup logging mechanism + +The driver should probably be using the standard kernel logging mechanisms +such as dev_info, dev_dbg, and friends. + +7) Documentation + +A short top-down description of this driver's architecture (function of +kthreads, userspace, limitations) could be very helpful for reviewers. diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c index b59ef14890aa..afdd3e944f3f 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c @@ -77,7 +77,17 @@ struct vchiq_pagelist_info { }; static void __iomem *g_regs; -static unsigned int g_cache_line_size = sizeof(CACHE_LINE_SIZE); +/* This value is the size of the L2 cache lines as understood by the + * VPU firmware, which determines the required alignment of the + * offsets/sizes in pagelists. + * + * Modern VPU firmware looks for a DT "cache-line-size" property in + * the VCHIQ node and will overwrite it with the actual L2 cache size, + * which the kernel must then respect. That property was rejected + * upstream, so we have to use the VPU firmware's compatibility value + * of 32. + */ +static unsigned int g_cache_line_size = 32; static unsigned int g_fragments_size; static char *g_fragments_base; static char *g_free_fragments; @@ -117,14 +127,6 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state) if (err < 0) return err; - err = of_property_read_u32(dev->of_node, "cache-line-size", - &g_cache_line_size); - - if (err) { - dev_err(dev, "Missing cache-line-size property\n"); - return -ENODEV; - } - g_fragments_size = 2 * g_cache_line_size; /* Allocate space for the channels in coherent memory */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index c2c440009cac..24d456b0a6f0 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -193,6 +193,355 @@ static const char *const ioctl_names[] = { vchiq_static_assert(ARRAY_SIZE(ioctl_names) == (VCHIQ_IOC_MAX + 1)); +static VCHIQ_STATUS_T +vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, + unsigned int size, VCHIQ_BULK_DIR_T dir); + +#define VCHIQ_INIT_RETRIES 10 +VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out) +{ + VCHIQ_STATUS_T status = VCHIQ_ERROR; + VCHIQ_STATE_T *state; + VCHIQ_INSTANCE_T instance = NULL; + int i; + + vchiq_log_trace(vchiq_core_log_level, "%s called", __func__); + + /* VideoCore may not be ready due to boot up timing. + * It may never be ready if kernel and firmware are mismatched,so don't + * block forever. + */ + for (i = 0; i < VCHIQ_INIT_RETRIES; i++) { + state = vchiq_get_state(); + if (state) + break; + udelay(500); + } + if (i == VCHIQ_INIT_RETRIES) { + vchiq_log_error(vchiq_core_log_level, + "%s: videocore not initialized\n", __func__); + goto failed; + } else if (i > 0) { + vchiq_log_warning(vchiq_core_log_level, + "%s: videocore initialized after %d retries\n", + __func__, i); + } + + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) { + vchiq_log_error(vchiq_core_log_level, + "%s: error allocating vchiq instance\n", __func__); + goto failed; + } + + instance->connected = 0; + instance->state = state; + mutex_init(&instance->bulk_waiter_list_mutex); + INIT_LIST_HEAD(&instance->bulk_waiter_list); + + *instance_out = instance; + + status = VCHIQ_SUCCESS; + +failed: + vchiq_log_trace(vchiq_core_log_level, + "%s(%p): returning %d", __func__, instance, status); + + return status; +} +EXPORT_SYMBOL(vchiq_initialise); + +VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) +{ + VCHIQ_STATUS_T status; + VCHIQ_STATE_T *state = instance->state; + + vchiq_log_trace(vchiq_core_log_level, + "%s(%p) called", __func__, instance); + + if (mutex_lock_killable(&state->mutex) != 0) + return VCHIQ_RETRY; + + /* Remove all services */ + status = vchiq_shutdown_internal(state, instance); + + mutex_unlock(&state->mutex); + + vchiq_log_trace(vchiq_core_log_level, + "%s(%p): returning %d", __func__, instance, status); + + if (status == VCHIQ_SUCCESS) { + struct list_head *pos, *next; + + list_for_each_safe(pos, next, + &instance->bulk_waiter_list) { + struct bulk_waiter_node *waiter; + + waiter = list_entry(pos, + struct bulk_waiter_node, + list); + list_del(pos); + vchiq_log_info(vchiq_arm_log_level, + "bulk_waiter - cleaned up %pK for pid %d", + waiter, waiter->pid); + kfree(waiter); + } + kfree(instance); + } + + return status; +} +EXPORT_SYMBOL(vchiq_shutdown); + +static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) +{ + return instance->connected; +} + +VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) +{ + VCHIQ_STATUS_T status; + VCHIQ_STATE_T *state = instance->state; + + vchiq_log_trace(vchiq_core_log_level, + "%s(%p) called", __func__, instance); + + if (mutex_lock_killable(&state->mutex) != 0) { + vchiq_log_trace(vchiq_core_log_level, + "%s: call to mutex_lock failed", __func__); + status = VCHIQ_RETRY; + goto failed; + } + status = vchiq_connect_internal(state, instance); + + if (status == VCHIQ_SUCCESS) + instance->connected = 1; + + mutex_unlock(&state->mutex); + +failed: + vchiq_log_trace(vchiq_core_log_level, + "%s(%p): returning %d", __func__, instance, status); + + return status; +} +EXPORT_SYMBOL(vchiq_connect); + +VCHIQ_STATUS_T vchiq_add_service( + VCHIQ_INSTANCE_T instance, + const VCHIQ_SERVICE_PARAMS_T *params, + VCHIQ_SERVICE_HANDLE_T *phandle) +{ + VCHIQ_STATUS_T status; + VCHIQ_STATE_T *state = instance->state; + VCHIQ_SERVICE_T *service = NULL; + int srvstate; + + vchiq_log_trace(vchiq_core_log_level, + "%s(%p) called", __func__, instance); + + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; + + srvstate = vchiq_is_connected(instance) + ? VCHIQ_SRVSTATE_LISTENING + : VCHIQ_SRVSTATE_HIDDEN; + + service = vchiq_add_service_internal( + state, + params, + srvstate, + instance, + NULL); + + if (service) { + *phandle = service->handle; + status = VCHIQ_SUCCESS; + } else + status = VCHIQ_ERROR; + + vchiq_log_trace(vchiq_core_log_level, + "%s(%p): returning %d", __func__, instance, status); + + return status; +} +EXPORT_SYMBOL(vchiq_add_service); + +VCHIQ_STATUS_T vchiq_open_service( + VCHIQ_INSTANCE_T instance, + const VCHIQ_SERVICE_PARAMS_T *params, + VCHIQ_SERVICE_HANDLE_T *phandle) +{ + VCHIQ_STATUS_T status = VCHIQ_ERROR; + VCHIQ_STATE_T *state = instance->state; + VCHIQ_SERVICE_T *service = NULL; + + vchiq_log_trace(vchiq_core_log_level, + "%s(%p) called", __func__, instance); + + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; + + if (!vchiq_is_connected(instance)) + goto failed; + + service = vchiq_add_service_internal(state, + params, + VCHIQ_SRVSTATE_OPENING, + instance, + NULL); + + if (service) { + *phandle = service->handle; + status = vchiq_open_service_internal(service, current->pid); + if (status != VCHIQ_SUCCESS) { + vchiq_remove_service(service->handle); + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; + } + } + +failed: + vchiq_log_trace(vchiq_core_log_level, + "%s(%p): returning %d", __func__, instance, status); + + return status; +} +EXPORT_SYMBOL(vchiq_open_service); + +VCHIQ_STATUS_T +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, + unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) +{ + VCHIQ_STATUS_T status; + + switch (mode) { + case VCHIQ_BULK_MODE_NOCALLBACK: + case VCHIQ_BULK_MODE_CALLBACK: + status = vchiq_bulk_transfer(handle, + VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, + mode, VCHIQ_BULK_TRANSMIT); + break; + case VCHIQ_BULK_MODE_BLOCKING: + status = vchiq_blocking_bulk_transfer(handle, + (void *)data, size, VCHIQ_BULK_TRANSMIT); + break; + default: + return VCHIQ_ERROR; + } + + return status; +} +EXPORT_SYMBOL(vchiq_bulk_transmit); + +VCHIQ_STATUS_T +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, + unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) +{ + VCHIQ_STATUS_T status; + + switch (mode) { + case VCHIQ_BULK_MODE_NOCALLBACK: + case VCHIQ_BULK_MODE_CALLBACK: + status = vchiq_bulk_transfer(handle, + VCHI_MEM_HANDLE_INVALID, data, size, userdata, + mode, VCHIQ_BULK_RECEIVE); + break; + case VCHIQ_BULK_MODE_BLOCKING: + status = vchiq_blocking_bulk_transfer(handle, + (void *)data, size, VCHIQ_BULK_RECEIVE); + break; + default: + return VCHIQ_ERROR; + } + + return status; +} +EXPORT_SYMBOL(vchiq_bulk_receive); + +static VCHIQ_STATUS_T +vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, + unsigned int size, VCHIQ_BULK_DIR_T dir) +{ + VCHIQ_INSTANCE_T instance; + VCHIQ_SERVICE_T *service; + VCHIQ_STATUS_T status; + struct bulk_waiter_node *waiter = NULL; + struct list_head *pos; + + service = find_service_by_handle(handle); + if (!service) + return VCHIQ_ERROR; + + instance = service->instance; + + unlock_service(service); + + mutex_lock(&instance->bulk_waiter_list_mutex); + list_for_each(pos, &instance->bulk_waiter_list) { + if (list_entry(pos, struct bulk_waiter_node, + list)->pid == current->pid) { + waiter = list_entry(pos, + struct bulk_waiter_node, + list); + list_del(pos); + break; + } + } + mutex_unlock(&instance->bulk_waiter_list_mutex); + + if (waiter) { + VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; + + if (bulk) { + /* This thread has an outstanding bulk transfer. */ + if ((bulk->data != data) || + (bulk->size != size)) { + /* This is not a retry of the previous one. + * Cancel the signal when the transfer + * completes. + */ + spin_lock(&bulk_waiter_spinlock); + bulk->userdata = NULL; + spin_unlock(&bulk_waiter_spinlock); + } + } + } + + if (!waiter) { + waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL); + if (!waiter) { + vchiq_log_error(vchiq_core_log_level, + "%s - out of memory", __func__); + return VCHIQ_ERROR; + } + } + + status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID, + data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING, + dir); + if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || + !waiter->bulk_waiter.bulk) { + VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; + + if (bulk) { + /* Cancel the signal when the transfer + * completes. + */ + spin_lock(&bulk_waiter_spinlock); + bulk->userdata = NULL; + spin_unlock(&bulk_waiter_spinlock); + } + kfree(waiter); + } else { + waiter->pid = current->pid; + mutex_lock(&instance->bulk_waiter_list_mutex); + list_add(&waiter->list, &instance->bulk_waiter_list); + mutex_unlock(&instance->bulk_waiter_list_mutex); + vchiq_log_info(vchiq_arm_log_level, + "saved bulk_waiter %pK for pid %d", + waiter, current->pid); + } + + return status; +} /**************************************************************************** * * add_completion @@ -3225,7 +3574,8 @@ static int vchiq_probe(struct platform_device *pdev) struct rpi_firmware *fw; int err; - fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0); + fw_node = of_find_compatible_node(NULL, NULL, + "raspberrypi,bcm2835-firmware"); if (!fw_node) { dev_err(&pdev->dev, "Missing firmware node\n"); return -ENOENT; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h deleted file mode 100644 index df645813bdae..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_build_info.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2010-2012 Broadcom. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -const char *vchiq_get_build_hostname(void); -const char *vchiq_get_build_version(void); -const char *vchiq_get_build_time(void); -const char *vchiq_get_build_date(void); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h index 0e270852900d..e4109a83e628 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h @@ -149,16 +149,6 @@ vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle, size_t size); extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service, VCHIQ_HEADER_T *header); -extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, - const void *data, unsigned int size, void *userdata); -extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, - void *data, unsigned int size, void *userdata); -extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle( - VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, - const void *offset, unsigned int size, void *userdata); -extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle( - VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle, - void *offset, unsigned int size, void *userdata); extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, const void *data, unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c deleted file mode 100644 index 43c89a08bda9..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c +++ /dev/null @@ -1,431 +0,0 @@ -/** - * Copyright (c) 2010-2012 Broadcom. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* ---- Include Files ---------------------------------------------------- */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> - -#include "vchiq_core.h" -#include "vchiq_arm.h" -#include "vchiq_killable.h" - -/* ---- Public Variables ------------------------------------------------- */ - -/* ---- Private Constants and Types -------------------------------------- */ - -struct bulk_waiter_node { - struct bulk_waiter bulk_waiter; - int pid; - struct list_head list; -}; - -struct vchiq_instance_struct { - VCHIQ_STATE_T *state; - - int connected; - - struct list_head bulk_waiter_list; - struct mutex bulk_waiter_list_mutex; -}; - -static VCHIQ_STATUS_T -vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, - unsigned int size, VCHIQ_BULK_DIR_T dir); - -#define VCHIQ_INIT_RETRIES 10 -VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out) -{ - VCHIQ_STATUS_T status = VCHIQ_ERROR; - VCHIQ_STATE_T *state; - VCHIQ_INSTANCE_T instance = NULL; - int i; - - vchiq_log_trace(vchiq_core_log_level, "%s called", __func__); - - /* VideoCore may not be ready due to boot up timing. - * It may never be ready if kernel and firmware are mismatched,so don't - * block forever. - */ - for (i = 0; i < VCHIQ_INIT_RETRIES; i++) { - state = vchiq_get_state(); - if (state) - break; - udelay(500); - } - if (i == VCHIQ_INIT_RETRIES) { - vchiq_log_error(vchiq_core_log_level, - "%s: videocore not initialized\n", __func__); - goto failed; - } else if (i > 0) { - vchiq_log_warning(vchiq_core_log_level, - "%s: videocore initialized after %d retries\n", - __func__, i); - } - - instance = kzalloc(sizeof(*instance), GFP_KERNEL); - if (!instance) { - vchiq_log_error(vchiq_core_log_level, - "%s: error allocating vchiq instance\n", __func__); - goto failed; - } - - instance->connected = 0; - instance->state = state; - mutex_init(&instance->bulk_waiter_list_mutex); - INIT_LIST_HEAD(&instance->bulk_waiter_list); - - *instance_out = instance; - - status = VCHIQ_SUCCESS; - -failed: - vchiq_log_trace(vchiq_core_log_level, - "%s(%p): returning %d", __func__, instance, status); - - return status; -} -EXPORT_SYMBOL(vchiq_initialise); - -VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) -{ - VCHIQ_STATUS_T status; - VCHIQ_STATE_T *state = instance->state; - - vchiq_log_trace(vchiq_core_log_level, - "%s(%p) called", __func__, instance); - - if (mutex_lock_killable(&state->mutex) != 0) - return VCHIQ_RETRY; - - /* Remove all services */ - status = vchiq_shutdown_internal(state, instance); - - mutex_unlock(&state->mutex); - - vchiq_log_trace(vchiq_core_log_level, - "%s(%p): returning %d", __func__, instance, status); - - if (status == VCHIQ_SUCCESS) { - struct list_head *pos, *next; - - list_for_each_safe(pos, next, - &instance->bulk_waiter_list) { - struct bulk_waiter_node *waiter; - - waiter = list_entry(pos, - struct bulk_waiter_node, - list); - list_del(pos); - vchiq_log_info(vchiq_arm_log_level, - "bulk_waiter - cleaned up %pK for pid %d", - waiter, waiter->pid); - kfree(waiter); - } - kfree(instance); - } - - return status; -} -EXPORT_SYMBOL(vchiq_shutdown); - -static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) -{ - return instance->connected; -} - -VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) -{ - VCHIQ_STATUS_T status; - VCHIQ_STATE_T *state = instance->state; - - vchiq_log_trace(vchiq_core_log_level, - "%s(%p) called", __func__, instance); - - if (mutex_lock_killable(&state->mutex) != 0) { - vchiq_log_trace(vchiq_core_log_level, - "%s: call to mutex_lock failed", __func__); - status = VCHIQ_RETRY; - goto failed; - } - status = vchiq_connect_internal(state, instance); - - if (status == VCHIQ_SUCCESS) - instance->connected = 1; - - mutex_unlock(&state->mutex); - -failed: - vchiq_log_trace(vchiq_core_log_level, - "%s(%p): returning %d", __func__, instance, status); - - return status; -} -EXPORT_SYMBOL(vchiq_connect); - -VCHIQ_STATUS_T vchiq_add_service( - VCHIQ_INSTANCE_T instance, - const VCHIQ_SERVICE_PARAMS_T *params, - VCHIQ_SERVICE_HANDLE_T *phandle) -{ - VCHIQ_STATUS_T status; - VCHIQ_STATE_T *state = instance->state; - VCHIQ_SERVICE_T *service = NULL; - int srvstate; - - vchiq_log_trace(vchiq_core_log_level, - "%s(%p) called", __func__, instance); - - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; - - srvstate = vchiq_is_connected(instance) - ? VCHIQ_SRVSTATE_LISTENING - : VCHIQ_SRVSTATE_HIDDEN; - - service = vchiq_add_service_internal( - state, - params, - srvstate, - instance, - NULL); - - if (service) { - *phandle = service->handle; - status = VCHIQ_SUCCESS; - } else - status = VCHIQ_ERROR; - - vchiq_log_trace(vchiq_core_log_level, - "%s(%p): returning %d", __func__, instance, status); - - return status; -} -EXPORT_SYMBOL(vchiq_add_service); - -VCHIQ_STATUS_T vchiq_open_service( - VCHIQ_INSTANCE_T instance, - const VCHIQ_SERVICE_PARAMS_T *params, - VCHIQ_SERVICE_HANDLE_T *phandle) -{ - VCHIQ_STATUS_T status = VCHIQ_ERROR; - VCHIQ_STATE_T *state = instance->state; - VCHIQ_SERVICE_T *service = NULL; - - vchiq_log_trace(vchiq_core_log_level, - "%s(%p) called", __func__, instance); - - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; - - if (!vchiq_is_connected(instance)) - goto failed; - - service = vchiq_add_service_internal(state, - params, - VCHIQ_SRVSTATE_OPENING, - instance, - NULL); - - if (service) { - *phandle = service->handle; - status = vchiq_open_service_internal(service, current->pid); - if (status != VCHIQ_SUCCESS) { - vchiq_remove_service(service->handle); - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; - } - } - -failed: - vchiq_log_trace(vchiq_core_log_level, - "%s(%p): returning %d", __func__, instance, status); - - return status; -} -EXPORT_SYMBOL(vchiq_open_service); - -VCHIQ_STATUS_T -vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, - const void *data, unsigned int size, void *userdata) -{ - return vchiq_bulk_transfer(handle, - VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, - VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT); -} -EXPORT_SYMBOL(vchiq_queue_bulk_transmit); - -VCHIQ_STATUS_T -vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, - unsigned int size, void *userdata) -{ - return vchiq_bulk_transfer(handle, - VCHI_MEM_HANDLE_INVALID, data, size, userdata, - VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE); -} -EXPORT_SYMBOL(vchiq_queue_bulk_receive); - -VCHIQ_STATUS_T -vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) -{ - VCHIQ_STATUS_T status; - - switch (mode) { - case VCHIQ_BULK_MODE_NOCALLBACK: - case VCHIQ_BULK_MODE_CALLBACK: - status = vchiq_bulk_transfer(handle, - VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, - mode, VCHIQ_BULK_TRANSMIT); - break; - case VCHIQ_BULK_MODE_BLOCKING: - status = vchiq_blocking_bulk_transfer(handle, - (void *)data, size, VCHIQ_BULK_TRANSMIT); - break; - default: - return VCHIQ_ERROR; - } - - return status; -} -EXPORT_SYMBOL(vchiq_bulk_transmit); - -VCHIQ_STATUS_T -vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) -{ - VCHIQ_STATUS_T status; - - switch (mode) { - case VCHIQ_BULK_MODE_NOCALLBACK: - case VCHIQ_BULK_MODE_CALLBACK: - status = vchiq_bulk_transfer(handle, - VCHI_MEM_HANDLE_INVALID, data, size, userdata, - mode, VCHIQ_BULK_RECEIVE); - break; - case VCHIQ_BULK_MODE_BLOCKING: - status = vchiq_blocking_bulk_transfer(handle, - (void *)data, size, VCHIQ_BULK_RECEIVE); - break; - default: - return VCHIQ_ERROR; - } - - return status; -} -EXPORT_SYMBOL(vchiq_bulk_receive); - -static VCHIQ_STATUS_T -vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, - unsigned int size, VCHIQ_BULK_DIR_T dir) -{ - VCHIQ_INSTANCE_T instance; - VCHIQ_SERVICE_T *service; - VCHIQ_STATUS_T status; - struct bulk_waiter_node *waiter = NULL; - struct list_head *pos; - - service = find_service_by_handle(handle); - if (!service) - return VCHIQ_ERROR; - - instance = service->instance; - - unlock_service(service); - - mutex_lock(&instance->bulk_waiter_list_mutex); - list_for_each(pos, &instance->bulk_waiter_list) { - if (list_entry(pos, struct bulk_waiter_node, - list)->pid == current->pid) { - waiter = list_entry(pos, - struct bulk_waiter_node, - list); - list_del(pos); - break; - } - } - mutex_unlock(&instance->bulk_waiter_list_mutex); - - if (waiter) { - VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; - - if (bulk) { - /* This thread has an outstanding bulk transfer. */ - if ((bulk->data != data) || - (bulk->size != size)) { - /* This is not a retry of the previous one. - * Cancel the signal when the transfer - * completes. - */ - spin_lock(&bulk_waiter_spinlock); - bulk->userdata = NULL; - spin_unlock(&bulk_waiter_spinlock); - } - } - } - - if (!waiter) { - waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL); - if (!waiter) { - vchiq_log_error(vchiq_core_log_level, - "%s - out of memory", __func__); - return VCHIQ_ERROR; - } - } - - status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID, - data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING, - dir); - if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || - !waiter->bulk_waiter.bulk) { - VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; - - if (bulk) { - /* Cancel the signal when the transfer - * completes. - */ - spin_lock(&bulk_waiter_spinlock); - bulk->userdata = NULL; - spin_unlock(&bulk_waiter_spinlock); - } - kfree(waiter); - } else { - waiter->pid = current->pid; - mutex_lock(&instance->bulk_waiter_list_mutex); - list_add(&waiter->list, &instance->bulk_waiter_list); - mutex_unlock(&instance->bulk_waiter_list_mutex); - vchiq_log_info(vchiq_arm_log_level, - "saved bulk_waiter %pK for pid %d", - waiter, current->pid); - } - - return status; -} diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h deleted file mode 100644 index c233b866725b..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_memdrv.h +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2010-2012 Broadcom. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef VCHIQ_MEMDRV_H -#define VCHIQ_MEMDRV_H - -/* ---- Include Files ----------------------------------------------------- */ - -#include <linux/kernel.h> -#include "vchiq_if.h" - -/* ---- Constants and Types ---------------------------------------------- */ - -/* ---- Variable Externs ------------------------------------------------- */ - -/* ---- Function Prototypes ---------------------------------------------- */ - -VCHIQ_STATUS_T vchiq_memdrv_initialise(void); - -VCHIQ_STATUS_T vchiq_userdrv_create_instance( - const VCHIQ_PLATFORM_DATA_T * platform_data); - -VCHIQ_STATUS_T vchiq_userdrv_suspend( - const VCHIQ_PLATFORM_DATA_T * platform_data); - -VCHIQ_STATUS_T vchiq_userdrv_resume( - const VCHIQ_PLATFORM_DATA_T * platform_data); - -#endif diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h index 926c247fd9d3..bec411061554 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_pagelist.h @@ -34,7 +34,6 @@ #ifndef VCHIQ_PAGELIST_H #define VCHIQ_PAGELIST_H -#define CACHE_LINE_SIZE 32 #define PAGELIST_WRITE 0 #define PAGELIST_READ 1 #define PAGELIST_READ_WITH_FRAGMENTS 2 @@ -49,9 +48,4 @@ typedef struct pagelist_struct { */ } PAGELIST_T; -typedef struct fragments_struct { - char headbuf[CACHE_LINE_SIZE]; - char tailbuf[CACHE_LINE_SIZE]; -} FRAGMENTS_T; - #endif /* VCHIQ_PAGELIST_H */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c deleted file mode 100644 index 994b81798134..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_version.c +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (c) 2010-2012 Broadcom. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "vchiq_build_info.h" -#include <linux/broadcom/vc_debug_sym.h> - -VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_hostname, "dc4-arm-01"); -VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_version, "9245b4c35b99b3870e1f7dc598c5692b3c66a6f0 (tainted)"); -VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_time, __TIME__); -VC_DEBUG_DECLARE_STRING_VAR(vchiq_build_date, __DATE__); - -const char *vchiq_get_build_hostname(void) -{ - return vchiq_build_hostname; -} - -const char *vchiq_get_build_version(void) -{ - return vchiq_build_version; -} - -const char *vchiq_get_build_date(void) -{ - return vchiq_build_date; -} - -const char *vchiq_get_build_time(void) -{ - return vchiq_build_time; -} diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 3242dee8246f..6a33aaa1a49f 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -558,7 +558,7 @@ static int vme_user_probe(struct vme_dev *vdev) vme_user_cdev->owner = THIS_MODULE; err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS); if (err) - goto err_char; + goto err_class; /* Request slave resources and allocate buffers (128kB wide) */ for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { @@ -618,7 +618,7 @@ static int vme_user_probe(struct vme_dev *vdev) if (IS_ERR(vme_user_sysfs_class)) { dev_err(&vdev->dev, "Error creating vme_user class.\n"); err = PTR_ERR(vme_user_sysfs_class); - goto err_class; + goto err_master; } /* Add sysfs Entries */ diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h index b8ee33dcb352..30d9e9d20a39 100644 --- a/drivers/staging/vt6655/baseband.h +++ b/drivers/staging/vt6655/baseband.h @@ -46,13 +46,10 @@ #define TOP_RATE_2M 0x00200000 #define TOP_RATE_1M 0x00100000 -unsigned int -BBuGetFrameTime( - unsigned char byPreambleType, - unsigned char byPktType, - unsigned int cbFrameLength, - unsigned short wRate -); +unsigned int BBuGetFrameTime(unsigned char byPreambleType, + unsigned char byPktType, + unsigned int cbFrameLength, + unsigned short wRate); void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length, u16 tx_rate, u8 pkt_type, struct vnt_phy_field *phy); diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h index 487039a64587..5884fd56153e 100644 --- a/drivers/staging/vt6655/card.h +++ b/drivers/staging/vt6655/card.h @@ -39,19 +39,6 @@ #define CB_MAX_CHANNEL_5G 42 #define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G + CB_MAX_CHANNEL_5G) -typedef enum _CARD_PKT_TYPE { - PKT_TYPE_802_11_BCN, - PKT_TYPE_802_11_MNG, - PKT_TYPE_802_11_DATA, - PKT_TYPE_802_11_ALL -} CARD_PKT_TYPE, *PCARD_PKT_TYPE; - -typedef enum _CARD_STATUS_TYPE { - CARD_STATUS_MEDIA_CONNECT, - CARD_STATUS_MEDIA_DISCONNECT, - CARD_STATUS_PMKID -} CARD_STATUS_TYPE, *PCARD_STATUS_TYPE; - struct vnt_private; void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type); diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h index 73f904b51b96..6b41c74f7c2a 100644 --- a/drivers/staging/vt6655/device_cfg.h +++ b/drivers/staging/vt6655/device_cfg.h @@ -16,13 +16,6 @@ #include <linux/types.h> -typedef -struct _version { - unsigned char major; - unsigned char minor; - unsigned char build; -} version_t, *pversion_t; - #define VID_TABLE_SIZE 64 #define MCAST_TABLE_SIZE 64 #define MCAM_SIZE 32 @@ -52,8 +45,4 @@ struct _version { #define PKT_BUF_SZ 2390 -typedef enum _chip_type { - VT3253 = 1 -} CHIP_TYPE, *PCHIP_TYPE; - #endif diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 0dc902022a91..fbc4bc68144c 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -543,7 +543,7 @@ static void device_init_rd0_ring(struct vnt_private *priv) if (!device_alloc_rx_buf(priv, desc)) dev_err(&priv->pcid->dev, "can not alloc rx bufs\n"); - desc->next = &(priv->aRD0Ring[(i + 1) % priv->opts.rx_descs0]); + desc->next = &priv->aRD0Ring[(i + 1) % priv->opts.rx_descs0]; desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc)); } @@ -567,7 +567,7 @@ static void device_init_rd1_ring(struct vnt_private *priv) if (!device_alloc_rx_buf(priv, desc)) dev_err(&priv->pcid->dev, "can not alloc rx bufs\n"); - desc->next = &(priv->aRD1Ring[(i+1) % priv->opts.rx_descs1]); + desc->next = &priv->aRD1Ring[(i+1) % priv->opts.rx_descs1]; desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_rx_desc)); } @@ -581,7 +581,7 @@ static void device_free_rd0_ring(struct vnt_private *priv) int i; for (i = 0; i < priv->opts.rx_descs0; i++) { - struct vnt_rx_desc *desc = &(priv->aRD0Ring[i]); + struct vnt_rx_desc *desc = &priv->aRD0Ring[i]; struct vnt_rd_info *rd_info = desc->rd_info; dma_unmap_single(&priv->pcid->dev, rd_info->skb_dma, diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 9aa4d5262aaa..9c4a5325afc7 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -320,7 +320,6 @@ s_uGetDataDuration( uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); else uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck); - } if (bNeedAck) { @@ -490,11 +489,9 @@ s_uFillDataHead( bool is_pspoll ) { - if (!pTxDataHead) return 0; - if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { if (byFBOption == AUTO_FB_NONE) { struct vnt_tx_datahead_g *buf = pTxDataHead; @@ -618,7 +615,6 @@ s_uFillDataHead( return 0; } - static void s_vFillRTSHead( @@ -966,7 +962,7 @@ s_vGenerateTxParameter( return; if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { - if (pvRTS != NULL) { /* RTS_need */ + if (pvRTS) { /* RTS_need */ /* Fill RsvTime */ struct vnt_rrv_time_rts *buf = pvRrvTime; @@ -988,7 +984,7 @@ s_vGenerateTxParameter( s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption); } } else if (byPktType == PK_TYPE_11A) { - if (pvRTS != NULL) {/* RTS_need, non PCF mode */ + if (pvRTS) {/* RTS_need, non PCF mode */ struct vnt_rrv_time_ab *buf = pvRrvTime; buf->rts_rrv_time = s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate); @@ -1002,7 +998,7 @@ s_vGenerateTxParameter( buf->rrv_time = vnt_rxtx_rsvtime_le16(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK); } } else if (byPktType == PK_TYPE_11B) { - if (pvRTS != NULL) {/* RTS_need, non PCF mode */ + if (pvRTS) {/* RTS_need, non PCF mode */ struct vnt_rrv_time_ab *buf = pvRrvTime; buf->rts_rrv_time = s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate); @@ -1080,7 +1076,6 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType, else if (fifo_ctl & FIFOCTL_AUTO_FB_1) byFBOption = AUTO_FB_1; - /* Set RrvTime/RTS/CTS Buffer */ wTxBufSize = sizeof(struct vnt_tx_fifo_head); if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {/* 802.11g packet */ @@ -1389,7 +1384,6 @@ int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx, else if (priv->byAutoFBCtrl == AUTO_FB_1) tx_buffer_head->fifo_ctl |= cpu_to_le16(FIFOCTL_AUTO_FB_1); - } tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_NONFRAG); diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c index 273176386a51..5bbc56f8779e 100644 --- a/drivers/staging/vt6656/usbpipe.c +++ b/drivers/staging/vt6656/usbpipe.c @@ -194,9 +194,6 @@ static void vnt_submit_rx_urb_complete(struct urb *urb) if (vnt_rx_data(priv, rcb, urb->actual_length)) { rcb->skb = dev_alloc_skb(priv->rx_buf_sz); if (!rcb->skb) { - dev_dbg(&priv->usb->dev, - "Failed to re-alloc rx skb\n"); - rcb->in_use = false; return; } diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index e98fc8e93011..db66b1cc80b3 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -148,19 +148,19 @@ static inline u8 get_from_ds(u8 *header) return ((header[1] & 0x02) >> 1); } -static inline void get_address1(u8 *pu8msa, u8 *addr) +static inline void get_address1(u8 *msa, u8 *addr) { - memcpy(addr, pu8msa + 4, 6); + memcpy(addr, msa + 4, 6); } -static inline void get_address2(u8 *pu8msa, u8 *addr) +static inline void get_address2(u8 *msa, u8 *addr) { - memcpy(addr, pu8msa + 10, 6); + memcpy(addr, msa + 10, 6); } -static inline void get_address3(u8 *pu8msa, u8 *addr) +static inline void get_address3(u8 *msa, u8 *addr) { - memcpy(addr, pu8msa + 16, 6); + memcpy(addr, msa + 16, 6); } static inline void get_BSSID(u8 *data, u8 *bssid) @@ -238,30 +238,30 @@ static inline u16 get_asoc_id(u8 *data) return asoc_id; } -static u8 *get_tim_elm(u8 *pu8msa, u16 rx_len, u16 tag_param_offset) +static u8 *get_tim_elm(u8 *msa, u16 rx_len, u16 tag_param_offset) { u16 index; index = tag_param_offset; while (index < (rx_len - FCS_LEN)) { - if (pu8msa[index] == ITIM) - return &pu8msa[index]; - index += (IE_HDR_LEN + pu8msa[index + 1]); + if (msa[index] == ITIM) + return &msa[index]; + index += (IE_HDR_LEN + msa[index + 1]); } return NULL; } -static u8 get_current_channel_802_11n(u8 *pu8msa, u16 rx_len) +static u8 get_current_channel_802_11n(u8 *msa, u16 rx_len) { u16 index; index = TAG_PARAM_OFFSET; while (index < (rx_len - FCS_LEN)) { - if (pu8msa[index] == IDSPARMS) - return pu8msa[index + 2]; - index += pu8msa[index + 1] + IE_HDR_LEN; + if (msa[index] == IDSPARMS) + return msa[index + 2]; + index += msa[index + 1] + IE_HDR_LEN; } return 0; @@ -320,8 +320,8 @@ s32 wilc_parse_network_info(u8 *msg_buffer, get_ssid(msa, network_info->ssid, &network_info->ssid_len); get_BSSID(msa, network_info->bssid); - network_info->ch = get_current_channel_802_11n(msa, - rx_len + FCS_LEN); + network_info->ch = get_current_channel_802_11n(msa, rx_len + + FCS_LEN); index = MAC_HDR_LEN + TIME_STAMP_LEN; diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 358354b3a2b4..6b5300ca44a6 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -254,20 +254,13 @@ static u32 inactive_time; static u8 del_beacon; static u32 clients_count; -static u8 *join_req; -static u8 *info_element; -static u8 mode_11i; -static u8 auth_type; -static u32 join_req_size; -static u32 info_element_size; -static struct wilc_vif *join_req_vif; #define REAL_JOIN_REQ 0 #define FLUSHED_JOIN_REQ 1 #define FLUSHED_BYTE_POS 79 -static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo); +static void *host_int_parse_join_bss_param(struct network_info *info); static int host_int_get_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx); -static s32 Handle_ScanDone(struct wilc_vif *vif, enum scan_event enuEvent); +static s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt); static void host_if_work(struct work_struct *work); /*! @@ -469,8 +462,7 @@ static void handle_get_mac_address(struct wilc_vif *vif, complete(&hif_wait_response); } -static void handle_cfg_param(struct wilc_vif *vif, - struct cfg_param_attr *cfg_param_attr) +static void handle_cfg_param(struct wilc_vif *vif, struct cfg_param_attr *param) { int ret = 0; struct wid wid_list[32]; @@ -479,12 +471,12 @@ static void handle_cfg_param(struct wilc_vif *vif, mutex_lock(&hif_drv->cfg_values_lock); - if (cfg_param_attr->flag & BSS_TYPE) { - u8 bss_type = cfg_param_attr->bss_type; + if (param->flag & BSS_TYPE) { + u8 bss_type = param->bss_type; if (bss_type < 6) { wid_list[i].id = WID_BSS_TYPE; - wid_list[i].val = (s8 *)&bss_type; + wid_list[i].val = (s8 *)¶m->bss_type; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); hif_drv->cfg_values.bss_type = bss_type; @@ -494,228 +486,244 @@ static void handle_cfg_param(struct wilc_vif *vif, } i++; } - if (cfg_param_attr->flag & AUTH_TYPE) { - if (cfg_param_attr->auth_type == 1 || - cfg_param_attr->auth_type == 2 || - cfg_param_attr->auth_type == 5) { + if (param->flag & AUTH_TYPE) { + u8 auth_type = param->auth_type; + + if (auth_type == 1 || auth_type == 2 || auth_type == 5) { wid_list[i].id = WID_AUTH_TYPE; - wid_list[i].val = (s8 *)&cfg_param_attr->auth_type; + wid_list[i].val = (s8 *)¶m->auth_type; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.auth_type = (u8)cfg_param_attr->auth_type; + hif_drv->cfg_values.auth_type = auth_type; } else { netdev_err(vif->ndev, "Impossible value\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & AUTHEN_TIMEOUT) { - if (cfg_param_attr->auth_timeout > 0 && - cfg_param_attr->auth_timeout < 65536) { + if (param->flag & AUTHEN_TIMEOUT) { + if (param->auth_timeout > 0) { wid_list[i].id = WID_AUTH_TIMEOUT; - wid_list[i].val = (s8 *)&cfg_param_attr->auth_timeout; + wid_list[i].val = (s8 *)¶m->auth_timeout; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.auth_timeout = cfg_param_attr->auth_timeout; + hif_drv->cfg_values.auth_timeout = param->auth_timeout; } else { netdev_err(vif->ndev, "Range(1 ~ 65535) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & POWER_MANAGEMENT) { - if (cfg_param_attr->power_mgmt_mode < 5) { + if (param->flag & POWER_MANAGEMENT) { + u8 pm_mode = param->power_mgmt_mode; + + if (pm_mode < 5) { wid_list[i].id = WID_POWER_MANAGEMENT; - wid_list[i].val = (s8 *)&cfg_param_attr->power_mgmt_mode; + wid_list[i].val = (s8 *)¶m->power_mgmt_mode; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.power_mgmt_mode = (u8)cfg_param_attr->power_mgmt_mode; + hif_drv->cfg_values.power_mgmt_mode = pm_mode; } else { netdev_err(vif->ndev, "Invalid power mode\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & RETRY_SHORT) { - if (cfg_param_attr->short_retry_limit > 0 && - cfg_param_attr->short_retry_limit < 256) { + if (param->flag & RETRY_SHORT) { + u16 retry_limit = param->short_retry_limit; + + if (retry_limit > 0 && retry_limit < 256) { wid_list[i].id = WID_SHORT_RETRY_LIMIT; - wid_list[i].val = (s8 *)&cfg_param_attr->short_retry_limit; + wid_list[i].val = (s8 *)¶m->short_retry_limit; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.short_retry_limit = cfg_param_attr->short_retry_limit; + hif_drv->cfg_values.short_retry_limit = retry_limit; } else { netdev_err(vif->ndev, "Range(1~256) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & RETRY_LONG) { - if (cfg_param_attr->long_retry_limit > 0 && - cfg_param_attr->long_retry_limit < 256) { + if (param->flag & RETRY_LONG) { + u16 limit = param->long_retry_limit; + + if (limit > 0 && limit < 256) { wid_list[i].id = WID_LONG_RETRY_LIMIT; - wid_list[i].val = (s8 *)&cfg_param_attr->long_retry_limit; + wid_list[i].val = (s8 *)¶m->long_retry_limit; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.long_retry_limit = cfg_param_attr->long_retry_limit; + hif_drv->cfg_values.long_retry_limit = limit; } else { netdev_err(vif->ndev, "Range(1~256) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & FRAG_THRESHOLD) { - if (cfg_param_attr->frag_threshold > 255 && - cfg_param_attr->frag_threshold < 7937) { + if (param->flag & FRAG_THRESHOLD) { + u16 frag_th = param->frag_threshold; + + if (frag_th > 255 && frag_th < 7937) { wid_list[i].id = WID_FRAG_THRESHOLD; - wid_list[i].val = (s8 *)&cfg_param_attr->frag_threshold; + wid_list[i].val = (s8 *)¶m->frag_threshold; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.frag_threshold = cfg_param_attr->frag_threshold; + hif_drv->cfg_values.frag_threshold = frag_th; } else { netdev_err(vif->ndev, "Threshold Range fail\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & RTS_THRESHOLD) { - if (cfg_param_attr->rts_threshold > 255 && - cfg_param_attr->rts_threshold < 65536) { + if (param->flag & RTS_THRESHOLD) { + u16 rts_th = param->rts_threshold; + + if (rts_th > 255) { wid_list[i].id = WID_RTS_THRESHOLD; - wid_list[i].val = (s8 *)&cfg_param_attr->rts_threshold; + wid_list[i].val = (s8 *)¶m->rts_threshold; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.rts_threshold = cfg_param_attr->rts_threshold; + hif_drv->cfg_values.rts_threshold = rts_th; } else { netdev_err(vif->ndev, "Threshold Range fail\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & PREAMBLE) { - if (cfg_param_attr->preamble_type < 3) { + if (param->flag & PREAMBLE) { + u16 preamble_type = param->preamble_type; + + if (param->preamble_type < 3) { wid_list[i].id = WID_PREAMBLE; - wid_list[i].val = (s8 *)&cfg_param_attr->preamble_type; + wid_list[i].val = (s8 *)¶m->preamble_type; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.preamble_type = cfg_param_attr->preamble_type; + hif_drv->cfg_values.preamble_type = preamble_type; } else { netdev_err(vif->ndev, "Preamle Range(0~2) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & SHORT_SLOT_ALLOWED) { - if (cfg_param_attr->short_slot_allowed < 2) { + if (param->flag & SHORT_SLOT_ALLOWED) { + u8 slot_allowed = param->short_slot_allowed; + + if (slot_allowed < 2) { wid_list[i].id = WID_SHORT_SLOT_ALLOWED; - wid_list[i].val = (s8 *)&cfg_param_attr->short_slot_allowed; + wid_list[i].val = (s8 *)¶m->short_slot_allowed; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.short_slot_allowed = (u8)cfg_param_attr->short_slot_allowed; + hif_drv->cfg_values.short_slot_allowed = slot_allowed; } else { netdev_err(vif->ndev, "Short slot(2) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & TXOP_PROT_DISABLE) { - if (cfg_param_attr->txop_prot_disabled < 2) { + if (param->flag & TXOP_PROT_DISABLE) { + u8 prot_disabled = param->txop_prot_disabled; + + if (param->txop_prot_disabled < 2) { wid_list[i].id = WID_11N_TXOP_PROT_DISABLE; - wid_list[i].val = (s8 *)&cfg_param_attr->txop_prot_disabled; + wid_list[i].val = (s8 *)¶m->txop_prot_disabled; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.txop_prot_disabled = (u8)cfg_param_attr->txop_prot_disabled; + hif_drv->cfg_values.txop_prot_disabled = prot_disabled; } else { netdev_err(vif->ndev, "TXOP prot disable\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & BEACON_INTERVAL) { - if (cfg_param_attr->beacon_interval > 0 && - cfg_param_attr->beacon_interval < 65536) { + if (param->flag & BEACON_INTERVAL) { + u16 beacon_interval = param->beacon_interval; + + if (beacon_interval > 0) { wid_list[i].id = WID_BEACON_INTERVAL; - wid_list[i].val = (s8 *)&cfg_param_attr->beacon_interval; + wid_list[i].val = (s8 *)¶m->beacon_interval; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.beacon_interval = cfg_param_attr->beacon_interval; + hif_drv->cfg_values.beacon_interval = beacon_interval; } else { netdev_err(vif->ndev, "Beacon interval(1~65535)fail\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & DTIM_PERIOD) { - if (cfg_param_attr->dtim_period > 0 && - cfg_param_attr->dtim_period < 256) { + if (param->flag & DTIM_PERIOD) { + if (param->dtim_period > 0 && param->dtim_period < 256) { wid_list[i].id = WID_DTIM_PERIOD; - wid_list[i].val = (s8 *)&cfg_param_attr->dtim_period; + wid_list[i].val = (s8 *)¶m->dtim_period; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.dtim_period = cfg_param_attr->dtim_period; + hif_drv->cfg_values.dtim_period = param->dtim_period; } else { netdev_err(vif->ndev, "DTIM range(1~255) fail\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & SITE_SURVEY) { - if (cfg_param_attr->site_survey_enabled < 3) { + if (param->flag & SITE_SURVEY) { + enum SITESURVEY enabled = param->site_survey_enabled; + + if (enabled < 3) { wid_list[i].id = WID_SITE_SURVEY; - wid_list[i].val = (s8 *)&cfg_param_attr->site_survey_enabled; + wid_list[i].val = (s8 *)¶m->site_survey_enabled; wid_list[i].type = WID_CHAR; wid_list[i].size = sizeof(char); - hif_drv->cfg_values.site_survey_enabled = (u8)cfg_param_attr->site_survey_enabled; + hif_drv->cfg_values.site_survey_enabled = enabled; } else { netdev_err(vif->ndev, "Site survey disable\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & SITE_SURVEY_SCAN_TIME) { - if (cfg_param_attr->site_survey_scan_time > 0 && - cfg_param_attr->site_survey_scan_time < 65536) { + if (param->flag & SITE_SURVEY_SCAN_TIME) { + u16 scan_time = param->site_survey_scan_time; + + if (scan_time > 0) { wid_list[i].id = WID_SITE_SURVEY_SCAN_TIME; - wid_list[i].val = (s8 *)&cfg_param_attr->site_survey_scan_time; + wid_list[i].val = (s8 *)¶m->site_survey_scan_time; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.site_survey_scan_time = cfg_param_attr->site_survey_scan_time; + hif_drv->cfg_values.site_survey_scan_time = scan_time; } else { netdev_err(vif->ndev, "Site scan time(1~65535) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & ACTIVE_SCANTIME) { - if (cfg_param_attr->active_scan_time > 0 && - cfg_param_attr->active_scan_time < 65536) { + if (param->flag & ACTIVE_SCANTIME) { + u16 active_scan_time = param->active_scan_time; + + if (active_scan_time > 0) { wid_list[i].id = WID_ACTIVE_SCAN_TIME; - wid_list[i].val = (s8 *)&cfg_param_attr->active_scan_time; + wid_list[i].val = (s8 *)¶m->active_scan_time; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.active_scan_time = cfg_param_attr->active_scan_time; + hif_drv->cfg_values.active_scan_time = active_scan_time; } else { netdev_err(vif->ndev, "Active time(1~65535) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & PASSIVE_SCANTIME) { - if (cfg_param_attr->passive_scan_time > 0 && - cfg_param_attr->passive_scan_time < 65536) { + if (param->flag & PASSIVE_SCANTIME) { + u16 time = param->passive_scan_time; + + if (time > 0) { wid_list[i].id = WID_PASSIVE_SCAN_TIME; - wid_list[i].val = (s8 *)&cfg_param_attr->passive_scan_time; + wid_list[i].val = (s8 *)¶m->passive_scan_time; wid_list[i].type = WID_SHORT; wid_list[i].size = sizeof(u16); - hif_drv->cfg_values.passive_scan_time = cfg_param_attr->passive_scan_time; + hif_drv->cfg_values.passive_scan_time = time; } else { netdev_err(vif->ndev, "Passive time(1~65535) over\n"); goto unlock; } i++; } - if (cfg_param_attr->flag & CURRENT_TX_RATE) { - enum CURRENT_TXRATE curr_tx_rate = cfg_param_attr->curr_tx_rate; + if (param->flag & CURRENT_TX_RATE) { + enum CURRENT_TXRATE curr_tx_rate = param->curr_tx_rate; if (curr_tx_rate == AUTORATE || curr_tx_rate == MBPS_1 || curr_tx_rate == MBPS_2 || curr_tx_rate == MBPS_5_5 || @@ -754,8 +762,9 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info) u32 i; u8 *buffer; u8 valuesize = 0; - u8 *pu8HdnNtwrksWidVal = NULL; + u8 *hdn_ntwk_wid_val = NULL; struct host_if_drv *hif_drv = vif->hif_drv; + struct hidden_network *hidden_net = &scan_info->hidden_network; hif_drv->usr_scan_req.scan_result = scan_info->result; hif_drv->usr_scan_req.arg = scan_info->arg; @@ -764,13 +773,13 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info) hif_drv->hif_state < HOST_IF_CONNECTED) { netdev_err(vif->ndev, "Already scan\n"); result = -EBUSY; - goto ERRORHANDLER; + goto error; } if (wilc_optaining_ip || wilc_connecting) { netdev_err(vif->ndev, "Don't do obss scan\n"); result = -EBUSY; - goto ERRORHANDLER; + goto error; } hif_drv->usr_scan_req.rcvd_ch_cnt = 0; @@ -778,19 +787,20 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info) wid_list[index].id = (u16)WID_SSID_PROBE_REQ; wid_list[index].type = WID_STR; - for (i = 0; i < scan_info->hidden_network.n_ssids; i++) - valuesize += ((scan_info->hidden_network.net_info[i].ssid_len) + 1); - pu8HdnNtwrksWidVal = kmalloc(valuesize + 1, GFP_KERNEL); - wid_list[index].val = pu8HdnNtwrksWidVal; + for (i = 0; i < hidden_net->n_ssids; i++) + valuesize += ((hidden_net->net_info[i].ssid_len) + 1); + hdn_ntwk_wid_val = kmalloc(valuesize + 1, GFP_KERNEL); + wid_list[index].val = hdn_ntwk_wid_val; if (wid_list[index].val) { buffer = wid_list[index].val; - *buffer++ = scan_info->hidden_network.n_ssids; + *buffer++ = hidden_net->n_ssids; - for (i = 0; i < scan_info->hidden_network.n_ssids; i++) { - *buffer++ = scan_info->hidden_network.net_info[i].ssid_len; - memcpy(buffer, scan_info->hidden_network.net_info[i].ssid, scan_info->hidden_network.net_info[i].ssid_len); - buffer += scan_info->hidden_network.net_info[i].ssid_len; + for (i = 0; i < hidden_net->n_ssids; i++) { + *buffer++ = hidden_net->net_info[i].ssid_len; + memcpy(buffer, hidden_net->net_info[i].ssid, + hidden_net->net_info[i].ssid_len); + buffer += hidden_net->net_info[i].ssid_len; } wid_list[index].size = (s32)(valuesize + 1); @@ -818,7 +828,7 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info) for (i = 0; i < scan_info->ch_list_len; i++) { if (scan_info->ch_freq_list[i] > 0) - scan_info->ch_freq_list[i] = scan_info->ch_freq_list[i] - 1; + scan_info->ch_freq_list[i] -= 1; } } @@ -844,10 +854,10 @@ static s32 handle_scan(struct wilc_vif *vif, struct scan_attr *scan_info) if (result) netdev_err(vif->ndev, "Failed to send scan parameters\n"); -ERRORHANDLER: +error: if (result) { del_timer(&hif_drv->scan_timer); - Handle_ScanDone(vif, SCAN_EVENT_ABORTED); + handle_scan_done(vif, SCAN_EVENT_ABORTED); } kfree(scan_info->ch_freq_list); @@ -858,24 +868,24 @@ ERRORHANDLER: kfree(scan_info->hidden_network.net_info); scan_info->hidden_network.net_info = NULL; - kfree(pu8HdnNtwrksWidVal); + kfree(hdn_ntwk_wid_val); return result; } -static s32 Handle_ScanDone(struct wilc_vif *vif, - enum scan_event enuEvent) +static s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt) { s32 result = 0; - u8 u8abort_running_scan; + u8 abort_running_scan; struct wid wid; struct host_if_drv *hif_drv = vif->hif_drv; + struct user_scan_req *scan_req; - if (enuEvent == SCAN_EVENT_ABORTED) { - u8abort_running_scan = 1; + if (evt == SCAN_EVENT_ABORTED) { + abort_running_scan = 1; wid.id = (u16)WID_ABORT_RUNNING_SCAN; wid.type = WID_CHAR; - wid.val = (s8 *)&u8abort_running_scan; + wid.val = (s8 *)&abort_running_scan; wid.size = sizeof(char); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, @@ -892,285 +902,280 @@ static s32 Handle_ScanDone(struct wilc_vif *vif, return result; } - if (hif_drv->usr_scan_req.scan_result) { - hif_drv->usr_scan_req.scan_result(enuEvent, NULL, - hif_drv->usr_scan_req.arg, NULL); - hif_drv->usr_scan_req.scan_result = NULL; + scan_req = &hif_drv->usr_scan_req; + if (scan_req->scan_result) { + scan_req->scan_result(evt, NULL, scan_req->arg, NULL); + scan_req->scan_result = NULL; } return result; } u8 wilc_connected_ssid[6] = {0}; -static s32 Handle_Connect(struct wilc_vif *vif, - struct connect_attr *pstrHostIFconnectAttr) +static s32 handle_connect(struct wilc_vif *vif, + struct connect_attr *conn_attr) { s32 result = 0; - struct wid strWIDList[8]; - u32 u32WidsCount = 0, dummyval = 0; - u8 *pu8CurrByte = NULL; - struct join_bss_param *ptstrJoinBssParam; + struct wid wid_list[8]; + u32 wid_cnt = 0, dummyval = 0; + u8 *cur_byte = NULL; + struct join_bss_param *bss_param; struct host_if_drv *hif_drv = vif->hif_drv; - if (memcmp(pstrHostIFconnectAttr->bssid, wilc_connected_ssid, ETH_ALEN) == 0) { + if (memcmp(conn_attr->bssid, wilc_connected_ssid, ETH_ALEN) == 0) { result = 0; netdev_err(vif->ndev, "Discard connect request\n"); return result; } - ptstrJoinBssParam = pstrHostIFconnectAttr->params; - if (!ptstrJoinBssParam) { + bss_param = conn_attr->params; + if (!bss_param) { netdev_err(vif->ndev, "Required BSSID not found\n"); result = -ENOENT; - goto ERRORHANDLER; + goto error; } - if (pstrHostIFconnectAttr->bssid) { - hif_drv->usr_conn_req.bssid = kmalloc(6, GFP_KERNEL); - memcpy(hif_drv->usr_conn_req.bssid, pstrHostIFconnectAttr->bssid, 6); + if (conn_attr->bssid) { + hif_drv->usr_conn_req.bssid = kmemdup(conn_attr->bssid, 6, + GFP_KERNEL); + if (!hif_drv->usr_conn_req.bssid) { + result = -ENOMEM; + goto error; + } } - hif_drv->usr_conn_req.ssid_len = pstrHostIFconnectAttr->ssid_len; - if (pstrHostIFconnectAttr->ssid) { - hif_drv->usr_conn_req.ssid = kmalloc(pstrHostIFconnectAttr->ssid_len + 1, GFP_KERNEL); + hif_drv->usr_conn_req.ssid_len = conn_attr->ssid_len; + if (conn_attr->ssid) { + hif_drv->usr_conn_req.ssid = kmalloc(conn_attr->ssid_len + 1, + GFP_KERNEL); + if (!hif_drv->usr_conn_req.ssid) { + result = -ENOMEM; + goto error; + } memcpy(hif_drv->usr_conn_req.ssid, - pstrHostIFconnectAttr->ssid, - pstrHostIFconnectAttr->ssid_len); - hif_drv->usr_conn_req.ssid[pstrHostIFconnectAttr->ssid_len] = '\0'; - } - - hif_drv->usr_conn_req.ies_len = pstrHostIFconnectAttr->ies_len; - if (pstrHostIFconnectAttr->ies) { - hif_drv->usr_conn_req.ies = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL); - memcpy(hif_drv->usr_conn_req.ies, - pstrHostIFconnectAttr->ies, - pstrHostIFconnectAttr->ies_len); - } - - hif_drv->usr_conn_req.security = pstrHostIFconnectAttr->security; - hif_drv->usr_conn_req.auth_type = pstrHostIFconnectAttr->auth_type; - hif_drv->usr_conn_req.conn_result = pstrHostIFconnectAttr->result; - hif_drv->usr_conn_req.arg = pstrHostIFconnectAttr->arg; - - strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT; - strWIDList[u32WidsCount].type = WID_INT; - strWIDList[u32WidsCount].size = sizeof(u32); - strWIDList[u32WidsCount].val = (s8 *)(&(dummyval)); - u32WidsCount++; - - strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT; - strWIDList[u32WidsCount].type = WID_INT; - strWIDList[u32WidsCount].size = sizeof(u32); - strWIDList[u32WidsCount].val = (s8 *)(&(dummyval)); - u32WidsCount++; - - strWIDList[u32WidsCount].id = WID_FAILED_COUNT; - strWIDList[u32WidsCount].type = WID_INT; - strWIDList[u32WidsCount].size = sizeof(u32); - strWIDList[u32WidsCount].val = (s8 *)(&(dummyval)); - u32WidsCount++; + conn_attr->ssid, + conn_attr->ssid_len); + hif_drv->usr_conn_req.ssid[conn_attr->ssid_len] = '\0'; + } - { - strWIDList[u32WidsCount].id = WID_INFO_ELEMENT_ASSOCIATE; - strWIDList[u32WidsCount].type = WID_BIN_DATA; - strWIDList[u32WidsCount].val = hif_drv->usr_conn_req.ies; - strWIDList[u32WidsCount].size = hif_drv->usr_conn_req.ies_len; - u32WidsCount++; - - if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) { - info_element_size = hif_drv->usr_conn_req.ies_len; - info_element = kmalloc(info_element_size, GFP_KERNEL); - memcpy(info_element, hif_drv->usr_conn_req.ies, - info_element_size); + hif_drv->usr_conn_req.ies_len = conn_attr->ies_len; + if (conn_attr->ies) { + hif_drv->usr_conn_req.ies = kmemdup(conn_attr->ies, + conn_attr->ies_len, + GFP_KERNEL); + if (!hif_drv->usr_conn_req.ies) { + result = -ENOMEM; + goto error; } } - strWIDList[u32WidsCount].id = (u16)WID_11I_MODE; - strWIDList[u32WidsCount].type = WID_CHAR; - strWIDList[u32WidsCount].size = sizeof(char); - strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.security; - u32WidsCount++; - - if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) - mode_11i = hif_drv->usr_conn_req.security; - strWIDList[u32WidsCount].id = (u16)WID_AUTH_TYPE; - strWIDList[u32WidsCount].type = WID_CHAR; - strWIDList[u32WidsCount].size = sizeof(char); - strWIDList[u32WidsCount].val = (s8 *)&hif_drv->usr_conn_req.auth_type; - u32WidsCount++; - - if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) - auth_type = (u8)hif_drv->usr_conn_req.auth_type; - - strWIDList[u32WidsCount].id = (u16)WID_JOIN_REQ_EXTENDED; - strWIDList[u32WidsCount].type = WID_STR; - strWIDList[u32WidsCount].size = 112; - strWIDList[u32WidsCount].val = kmalloc(strWIDList[u32WidsCount].size, GFP_KERNEL); - - if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) { - join_req_size = strWIDList[u32WidsCount].size; - join_req = kmalloc(join_req_size, GFP_KERNEL); - } - if (!strWIDList[u32WidsCount].val) { + hif_drv->usr_conn_req.security = conn_attr->security; + hif_drv->usr_conn_req.auth_type = conn_attr->auth_type; + hif_drv->usr_conn_req.conn_result = conn_attr->result; + hif_drv->usr_conn_req.arg = conn_attr->arg; + + wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)(&(dummyval)); + wid_cnt++; + + wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)(&(dummyval)); + wid_cnt++; + + wid_list[wid_cnt].id = WID_FAILED_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)(&(dummyval)); + wid_cnt++; + + wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE; + wid_list[wid_cnt].type = WID_BIN_DATA; + wid_list[wid_cnt].val = hif_drv->usr_conn_req.ies; + wid_list[wid_cnt].size = hif_drv->usr_conn_req.ies_len; + wid_cnt++; + + wid_list[wid_cnt].id = (u16)WID_11I_MODE; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.security; + wid_cnt++; + + wid_list[wid_cnt].id = (u16)WID_AUTH_TYPE; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&hif_drv->usr_conn_req.auth_type; + wid_cnt++; + + wid_list[wid_cnt].id = (u16)WID_JOIN_REQ_EXTENDED; + wid_list[wid_cnt].type = WID_STR; + wid_list[wid_cnt].size = 112; + wid_list[wid_cnt].val = kmalloc(wid_list[wid_cnt].size, GFP_KERNEL); + + if (!wid_list[wid_cnt].val) { result = -EFAULT; - goto ERRORHANDLER; + goto error; } - pu8CurrByte = strWIDList[u32WidsCount].val; + cur_byte = wid_list[wid_cnt].val; - if (pstrHostIFconnectAttr->ssid) { - memcpy(pu8CurrByte, pstrHostIFconnectAttr->ssid, pstrHostIFconnectAttr->ssid_len); - pu8CurrByte[pstrHostIFconnectAttr->ssid_len] = '\0'; + if (conn_attr->ssid) { + memcpy(cur_byte, conn_attr->ssid, conn_attr->ssid_len); + cur_byte[conn_attr->ssid_len] = '\0'; } - pu8CurrByte += MAX_SSID_LEN; - *(pu8CurrByte++) = INFRASTRUCTURE; + cur_byte += MAX_SSID_LEN; + *(cur_byte++) = INFRASTRUCTURE; - if (pstrHostIFconnectAttr->ch >= 1 && pstrHostIFconnectAttr->ch <= 14) { - *(pu8CurrByte++) = pstrHostIFconnectAttr->ch; + if (conn_attr->ch >= 1 && conn_attr->ch <= 14) { + *(cur_byte++) = conn_attr->ch; } else { netdev_err(vif->ndev, "Channel out of range\n"); - *(pu8CurrByte++) = 0xFF; + *(cur_byte++) = 0xFF; } - *(pu8CurrByte++) = (ptstrJoinBssParam->cap_info) & 0xFF; - *(pu8CurrByte++) = ((ptstrJoinBssParam->cap_info) >> 8) & 0xFF; + *(cur_byte++) = (bss_param->cap_info) & 0xFF; + *(cur_byte++) = ((bss_param->cap_info) >> 8) & 0xFF; - if (pstrHostIFconnectAttr->bssid) - memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6); - pu8CurrByte += 6; + if (conn_attr->bssid) + memcpy(cur_byte, conn_attr->bssid, 6); + cur_byte += 6; - if (pstrHostIFconnectAttr->bssid) - memcpy(pu8CurrByte, pstrHostIFconnectAttr->bssid, 6); - pu8CurrByte += 6; + if (conn_attr->bssid) + memcpy(cur_byte, conn_attr->bssid, 6); + cur_byte += 6; - *(pu8CurrByte++) = (ptstrJoinBssParam->beacon_period) & 0xFF; - *(pu8CurrByte++) = ((ptstrJoinBssParam->beacon_period) >> 8) & 0xFF; - *(pu8CurrByte++) = ptstrJoinBssParam->dtim_period; + *(cur_byte++) = (bss_param->beacon_period) & 0xFF; + *(cur_byte++) = ((bss_param->beacon_period) >> 8) & 0xFF; + *(cur_byte++) = bss_param->dtim_period; - memcpy(pu8CurrByte, ptstrJoinBssParam->supp_rates, MAX_RATES_SUPPORTED + 1); - pu8CurrByte += (MAX_RATES_SUPPORTED + 1); + memcpy(cur_byte, bss_param->supp_rates, MAX_RATES_SUPPORTED + 1); + cur_byte += (MAX_RATES_SUPPORTED + 1); - *(pu8CurrByte++) = ptstrJoinBssParam->wmm_cap; - *(pu8CurrByte++) = ptstrJoinBssParam->uapsd_cap; + *(cur_byte++) = bss_param->wmm_cap; + *(cur_byte++) = bss_param->uapsd_cap; - *(pu8CurrByte++) = ptstrJoinBssParam->ht_capable; - hif_drv->usr_conn_req.ht_capable = ptstrJoinBssParam->ht_capable; + *(cur_byte++) = bss_param->ht_capable; + hif_drv->usr_conn_req.ht_capable = bss_param->ht_capable; - *(pu8CurrByte++) = ptstrJoinBssParam->rsn_found; - *(pu8CurrByte++) = ptstrJoinBssParam->rsn_grp_policy; - *(pu8CurrByte++) = ptstrJoinBssParam->mode_802_11i; + *(cur_byte++) = bss_param->rsn_found; + *(cur_byte++) = bss_param->rsn_grp_policy; + *(cur_byte++) = bss_param->mode_802_11i; - memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_pcip_policy, sizeof(ptstrJoinBssParam->rsn_pcip_policy)); - pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_pcip_policy); + memcpy(cur_byte, bss_param->rsn_pcip_policy, + sizeof(bss_param->rsn_pcip_policy)); + cur_byte += sizeof(bss_param->rsn_pcip_policy); - memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_auth_policy, sizeof(ptstrJoinBssParam->rsn_auth_policy)); - pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_auth_policy); + memcpy(cur_byte, bss_param->rsn_auth_policy, + sizeof(bss_param->rsn_auth_policy)); + cur_byte += sizeof(bss_param->rsn_auth_policy); - memcpy(pu8CurrByte, ptstrJoinBssParam->rsn_cap, sizeof(ptstrJoinBssParam->rsn_cap)); - pu8CurrByte += sizeof(ptstrJoinBssParam->rsn_cap); + memcpy(cur_byte, bss_param->rsn_cap, sizeof(bss_param->rsn_cap)); + cur_byte += sizeof(bss_param->rsn_cap); - *(pu8CurrByte++) = REAL_JOIN_REQ; - *(pu8CurrByte++) = ptstrJoinBssParam->noa_enabled; + *(cur_byte++) = REAL_JOIN_REQ; + *(cur_byte++) = bss_param->noa_enabled; - if (ptstrJoinBssParam->noa_enabled) { - *(pu8CurrByte++) = (ptstrJoinBssParam->tsf) & 0xFF; - *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 8) & 0xFF; - *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 16) & 0xFF; - *(pu8CurrByte++) = ((ptstrJoinBssParam->tsf) >> 24) & 0xFF; + if (bss_param->noa_enabled) { + *(cur_byte++) = (bss_param->tsf) & 0xFF; + *(cur_byte++) = ((bss_param->tsf) >> 8) & 0xFF; + *(cur_byte++) = ((bss_param->tsf) >> 16) & 0xFF; + *(cur_byte++) = ((bss_param->tsf) >> 24) & 0xFF; - *(pu8CurrByte++) = ptstrJoinBssParam->opp_enabled; - *(pu8CurrByte++) = ptstrJoinBssParam->idx; + *(cur_byte++) = bss_param->opp_enabled; + *(cur_byte++) = bss_param->idx; - if (ptstrJoinBssParam->opp_enabled) - *(pu8CurrByte++) = ptstrJoinBssParam->ct_window; + if (bss_param->opp_enabled) + *(cur_byte++) = bss_param->ct_window; - *(pu8CurrByte++) = ptstrJoinBssParam->cnt; + *(cur_byte++) = bss_param->cnt; - memcpy(pu8CurrByte, ptstrJoinBssParam->duration, sizeof(ptstrJoinBssParam->duration)); - pu8CurrByte += sizeof(ptstrJoinBssParam->duration); + memcpy(cur_byte, bss_param->duration, + sizeof(bss_param->duration)); + cur_byte += sizeof(bss_param->duration); - memcpy(pu8CurrByte, ptstrJoinBssParam->interval, sizeof(ptstrJoinBssParam->interval)); - pu8CurrByte += sizeof(ptstrJoinBssParam->interval); + memcpy(cur_byte, bss_param->interval, + sizeof(bss_param->interval)); + cur_byte += sizeof(bss_param->interval); - memcpy(pu8CurrByte, ptstrJoinBssParam->start_time, sizeof(ptstrJoinBssParam->start_time)); - pu8CurrByte += sizeof(ptstrJoinBssParam->start_time); + memcpy(cur_byte, bss_param->start_time, + sizeof(bss_param->start_time)); + cur_byte += sizeof(bss_param->start_time); } - pu8CurrByte = strWIDList[u32WidsCount].val; - u32WidsCount++; + cur_byte = wid_list[wid_cnt].val; + wid_cnt++; - if (memcmp("DIRECT-", pstrHostIFconnectAttr->ssid, 7)) { - memcpy(join_req, pu8CurrByte, join_req_size); - join_req_vif = vif; - } - - if (pstrHostIFconnectAttr->bssid) + if (conn_attr->bssid) memcpy(wilc_connected_ssid, - pstrHostIFconnectAttr->bssid, ETH_ALEN); + conn_attr->bssid, ETH_ALEN); - result = wilc_send_config_pkt(vif, SET_CFG, strWIDList, - u32WidsCount, + result = wilc_send_config_pkt(vif, SET_CFG, wid_list, + wid_cnt, wilc_get_vif_idx(vif)); if (result) { netdev_err(vif->ndev, "failed to send config packet\n"); result = -EFAULT; - goto ERRORHANDLER; + goto error; } else { hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP; } -ERRORHANDLER: +error: if (result) { - struct connect_info strConnectInfo; + struct connect_info conn_info; del_timer(&hif_drv->connect_timer); - memset(&strConnectInfo, 0, sizeof(struct connect_info)); + memset(&conn_info, 0, sizeof(struct connect_info)); - if (pstrHostIFconnectAttr->result) { - if (pstrHostIFconnectAttr->bssid) - memcpy(strConnectInfo.bssid, pstrHostIFconnectAttr->bssid, 6); + if (conn_attr->result) { + if (conn_attr->bssid) + memcpy(conn_info.bssid, conn_attr->bssid, 6); - if (pstrHostIFconnectAttr->ies) { - strConnectInfo.req_ies_len = pstrHostIFconnectAttr->ies_len; - strConnectInfo.req_ies = kmalloc(pstrHostIFconnectAttr->ies_len, GFP_KERNEL); - memcpy(strConnectInfo.req_ies, - pstrHostIFconnectAttr->ies, - pstrHostIFconnectAttr->ies_len); + if (conn_attr->ies) { + conn_info.req_ies_len = conn_attr->ies_len; + conn_info.req_ies = kmalloc(conn_attr->ies_len, + GFP_KERNEL); + memcpy(conn_info.req_ies, + conn_attr->ies, + conn_attr->ies_len); } - pstrHostIFconnectAttr->result(CONN_DISCONN_EVENT_CONN_RESP, - &strConnectInfo, + conn_attr->result(CONN_DISCONN_EVENT_CONN_RESP, + &conn_info, MAC_DISCONNECTED, NULL, - pstrHostIFconnectAttr->arg); + conn_attr->arg); hif_drv->hif_state = HOST_IF_IDLE; - kfree(strConnectInfo.req_ies); - strConnectInfo.req_ies = NULL; + kfree(conn_info.req_ies); + conn_info.req_ies = NULL; } else { netdev_err(vif->ndev, "Connect callback is NULL\n"); } } - kfree(pstrHostIFconnectAttr->bssid); - pstrHostIFconnectAttr->bssid = NULL; + kfree(conn_attr->bssid); + conn_attr->bssid = NULL; - kfree(pstrHostIFconnectAttr->ssid); - pstrHostIFconnectAttr->ssid = NULL; + kfree(conn_attr->ssid); + conn_attr->ssid = NULL; - kfree(pstrHostIFconnectAttr->ies); - pstrHostIFconnectAttr->ies = NULL; + kfree(conn_attr->ies); + conn_attr->ies = NULL; - kfree(pu8CurrByte); + kfree(cur_byte); return result; } -static s32 Handle_ConnectTimeout(struct wilc_vif *vif) +static s32 handle_connect_timeout(struct wilc_vif *vif) { s32 result = 0; - struct connect_info strConnectInfo; + struct connect_info info; struct wid wid; - u16 u16DummyReasonCode = 0; + u16 dummy_reason_code = 0; struct host_if_drv *hif_drv = vif->hif_drv; if (!hif_drv) { @@ -1182,37 +1187,37 @@ static s32 Handle_ConnectTimeout(struct wilc_vif *vif) scan_while_connected = false; - memset(&strConnectInfo, 0, sizeof(struct connect_info)); + memset(&info, 0, sizeof(struct connect_info)); if (hif_drv->usr_conn_req.conn_result) { if (hif_drv->usr_conn_req.bssid) { - memcpy(strConnectInfo.bssid, + memcpy(info.bssid, hif_drv->usr_conn_req.bssid, 6); } if (hif_drv->usr_conn_req.ies) { - strConnectInfo.req_ies_len = hif_drv->usr_conn_req.ies_len; - strConnectInfo.req_ies = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL); - memcpy(strConnectInfo.req_ies, + info.req_ies_len = hif_drv->usr_conn_req.ies_len; + info.req_ies = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL); + memcpy(info.req_ies, hif_drv->usr_conn_req.ies, hif_drv->usr_conn_req.ies_len); } hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP, - &strConnectInfo, + &info, MAC_DISCONNECTED, NULL, hif_drv->usr_conn_req.arg); - kfree(strConnectInfo.req_ies); - strConnectInfo.req_ies = NULL; + kfree(info.req_ies); + info.req_ies = NULL; } else { netdev_err(vif->ndev, "Connect callback is NULL\n"); } wid.id = (u16)WID_DISCONNECT; wid.type = WID_CHAR; - wid.val = (s8 *)&u16DummyReasonCode; + wid.val = (s8 *)&dummy_reason_code; wid.size = sizeof(char); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, @@ -1231,382 +1236,380 @@ static s32 Handle_ConnectTimeout(struct wilc_vif *vif) eth_zero_addr(wilc_connected_ssid); - if (join_req && join_req_vif == vif) { - kfree(join_req); - join_req = NULL; - } - - if (info_element && join_req_vif == vif) { - kfree(info_element); - info_element = NULL; - } - return result; } -static s32 Handle_RcvdNtwrkInfo(struct wilc_vif *vif, - struct rcvd_net_info *pstrRcvdNetworkInfo) +static s32 handle_rcvd_ntwrk_info(struct wilc_vif *vif, + struct rcvd_net_info *rcvd_info) { u32 i; - bool bNewNtwrkFound; + bool found; s32 result = 0; - struct network_info *pstrNetworkInfo = NULL; - void *pJoinParams = NULL; + struct network_info *info = NULL; + void *params = NULL; struct host_if_drv *hif_drv = vif->hif_drv; + struct user_scan_req *scan_req = &hif_drv->usr_scan_req; - bNewNtwrkFound = true; + found = true; - if (hif_drv->usr_scan_req.scan_result) { - wilc_parse_network_info(pstrRcvdNetworkInfo->buffer, &pstrNetworkInfo); - if (!pstrNetworkInfo || - !hif_drv->usr_scan_req.scan_result) { - netdev_err(vif->ndev, "driver is null\n"); - result = -EINVAL; - goto done; - } + if (!scan_req->scan_result) + goto done; - for (i = 0; i < hif_drv->usr_scan_req.rcvd_ch_cnt; i++) { - if (memcmp(hif_drv->usr_scan_req.net_info[i].bssid, - pstrNetworkInfo->bssid, 6) == 0) { - if (pstrNetworkInfo->rssi <= hif_drv->usr_scan_req.net_info[i].rssi) { - goto done; - } else { - hif_drv->usr_scan_req.net_info[i].rssi = pstrNetworkInfo->rssi; - bNewNtwrkFound = false; - break; - } + wilc_parse_network_info(rcvd_info->buffer, &info); + if (!info || !scan_req->scan_result) { + netdev_err(vif->ndev, "driver is null\n"); + result = -EINVAL; + goto done; + } + + for (i = 0; i < scan_req->rcvd_ch_cnt; i++) { + if (memcmp(scan_req->net_info[i].bssid, info->bssid, 6) == 0) { + if (info->rssi <= scan_req->net_info[i].rssi) { + goto done; + } else { + scan_req->net_info[i].rssi = info->rssi; + found = false; + break; } } + } - if (bNewNtwrkFound) { - if (hif_drv->usr_scan_req.rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) { - hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].rssi = pstrNetworkInfo->rssi; + if (found) { + if (scan_req->rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) { + scan_req->net_info[scan_req->rcvd_ch_cnt].rssi = info->rssi; - memcpy(hif_drv->usr_scan_req.net_info[hif_drv->usr_scan_req.rcvd_ch_cnt].bssid, - pstrNetworkInfo->bssid, 6); + memcpy(scan_req->net_info[scan_req->rcvd_ch_cnt].bssid, + info->bssid, 6); - hif_drv->usr_scan_req.rcvd_ch_cnt++; + scan_req->rcvd_ch_cnt++; - pstrNetworkInfo->new_network = true; - pJoinParams = host_int_ParseJoinBssParam(pstrNetworkInfo); + info->new_network = true; + params = host_int_parse_join_bss_param(info); - hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, - hif_drv->usr_scan_req.arg, - pJoinParams); - } - } else { - pstrNetworkInfo->new_network = false; - hif_drv->usr_scan_req.scan_result(SCAN_EVENT_NETWORK_FOUND, pstrNetworkInfo, - hif_drv->usr_scan_req.arg, NULL); + scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info, + scan_req->arg, params); } + } else { + info->new_network = false; + scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, info, + scan_req->arg, NULL); } done: - kfree(pstrRcvdNetworkInfo->buffer); - pstrRcvdNetworkInfo->buffer = NULL; + kfree(rcvd_info->buffer); + rcvd_info->buffer = NULL; - if (pstrNetworkInfo) { - kfree(pstrNetworkInfo->ies); - kfree(pstrNetworkInfo); + if (info) { + kfree(info->ies); + kfree(info); } return result; } static s32 host_int_get_assoc_res_info(struct wilc_vif *vif, - u8 *pu8AssocRespInfo, - u32 u32MaxAssocRespInfoLen, - u32 *pu32RcvdAssocRespInfoLen); + u8 *assoc_resp_info, + u32 max_assoc_resp_info_len, + u32 *rcvd_assoc_resp_info_len); -static s32 Handle_RcvdGnrlAsyncInfo(struct wilc_vif *vif, - struct rcvd_async_info *pstrRcvdGnrlAsyncInfo) +static inline void host_int_free_user_conn_req(struct host_if_drv *hif_drv) { - s32 result = 0; - u8 u8MsgType = 0; - u8 u8MsgID = 0; - u16 u16MsgLen = 0; - u16 u16WidID = (u16)WID_NIL; - u8 u8WidLen = 0; - u8 u8MacStatus; - u8 u8MacStatusReasonCode; - u8 u8MacStatusAdditionalInfo; - struct connect_info strConnectInfo; - struct disconnect_info strDisconnectNotifInfo; - s32 s32Err = 0; + hif_drv->usr_conn_req.ssid_len = 0; + kfree(hif_drv->usr_conn_req.ssid); + hif_drv->usr_conn_req.ssid = NULL; + kfree(hif_drv->usr_conn_req.bssid); + hif_drv->usr_conn_req.bssid = NULL; + hif_drv->usr_conn_req.ies_len = 0; + kfree(hif_drv->usr_conn_req.ies); + hif_drv->usr_conn_req.ies = NULL; +} + +static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, + u8 mac_status) +{ + struct connect_resp_info *connect_resp_info = NULL; + struct connect_info conn_info; struct host_if_drv *hif_drv = vif->hif_drv; - if (!hif_drv) { - netdev_err(vif->ndev, "Driver handler is NULL\n"); - return -ENODEV; - } + memset(&conn_info, 0, sizeof(struct connect_info)); - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP || - hif_drv->hif_state == HOST_IF_CONNECTED || - hif_drv->usr_scan_req.scan_result) { - if (!pstrRcvdGnrlAsyncInfo->buffer || - !hif_drv->usr_conn_req.conn_result) { - netdev_err(vif->ndev, "driver is null\n"); - return -EINVAL; - } + if (mac_status == MAC_CONNECTED) { + u32 rcvd_assoc_resp_info_len; - u8MsgType = pstrRcvdGnrlAsyncInfo->buffer[0]; + memset(rcv_assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE); - if ('I' != u8MsgType) { - netdev_err(vif->ndev, "Received Message incorrect.\n"); - return -EFAULT; - } + host_int_get_assoc_res_info(vif, rcv_assoc_resp, + MAX_ASSOC_RESP_FRAME_SIZE, + &rcvd_assoc_resp_info_len); - u8MsgID = pstrRcvdGnrlAsyncInfo->buffer[1]; - u16MsgLen = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->buffer[2], pstrRcvdGnrlAsyncInfo->buffer[3]); - u16WidID = MAKE_WORD16(pstrRcvdGnrlAsyncInfo->buffer[4], pstrRcvdGnrlAsyncInfo->buffer[5]); - u8WidLen = pstrRcvdGnrlAsyncInfo->buffer[6]; - u8MacStatus = pstrRcvdGnrlAsyncInfo->buffer[7]; - u8MacStatusReasonCode = pstrRcvdGnrlAsyncInfo->buffer[8]; - u8MacStatusAdditionalInfo = pstrRcvdGnrlAsyncInfo->buffer[9]; - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { - u32 u32RcvdAssocRespInfoLen = 0; - struct connect_resp_info *pstrConnectRespInfo = NULL; - - memset(&strConnectInfo, 0, sizeof(struct connect_info)); - - if (u8MacStatus == MAC_CONNECTED) { - memset(rcv_assoc_resp, 0, MAX_ASSOC_RESP_FRAME_SIZE); - - host_int_get_assoc_res_info(vif, - rcv_assoc_resp, - MAX_ASSOC_RESP_FRAME_SIZE, - &u32RcvdAssocRespInfoLen); - - if (u32RcvdAssocRespInfoLen != 0) { - s32Err = wilc_parse_assoc_resp_info(rcv_assoc_resp, u32RcvdAssocRespInfoLen, - &pstrConnectRespInfo); - if (s32Err) { - netdev_err(vif->ndev, "wilc_parse_assoc_resp_info() returned error %d\n", s32Err); - } else { - strConnectInfo.status = pstrConnectRespInfo->status; - - if (strConnectInfo.status == SUCCESSFUL_STATUSCODE && pstrConnectRespInfo->ies) { - strConnectInfo.resp_ies_len = pstrConnectRespInfo->ies_len; - strConnectInfo.resp_ies = kmalloc(pstrConnectRespInfo->ies_len, GFP_KERNEL); - memcpy(strConnectInfo.resp_ies, pstrConnectRespInfo->ies, - pstrConnectRespInfo->ies_len); - } - - if (pstrConnectRespInfo) { - kfree(pstrConnectRespInfo->ies); - kfree(pstrConnectRespInfo); - } - } + if (rcvd_assoc_resp_info_len != 0) { + s32 err = 0; + + err = wilc_parse_assoc_resp_info(rcv_assoc_resp, rcvd_assoc_resp_info_len, + &connect_resp_info); + if (err) { + netdev_err(vif->ndev, + "wilc_parse_assoc_resp_info() returned error %d\n", + err); + } else { + conn_info.status = connect_resp_info->status; + + if (conn_info.status == SUCCESSFUL_STATUSCODE && + connect_resp_info->ies) { + conn_info.resp_ies = kmemdup(connect_resp_info->ies, + connect_resp_info->ies_len, + GFP_KERNEL); + if (conn_info.resp_ies) + conn_info.resp_ies_len = connect_resp_info->ies_len; } - } - if (u8MacStatus == MAC_CONNECTED && - strConnectInfo.status != SUCCESSFUL_STATUSCODE) { - netdev_err(vif->ndev, "Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n"); - eth_zero_addr(wilc_connected_ssid); - } else if (u8MacStatus == MAC_DISCONNECTED) { - netdev_err(vif->ndev, "Received MAC status is MAC_DISCONNECTED\n"); - eth_zero_addr(wilc_connected_ssid); + kfree(connect_resp_info->ies); + kfree(connect_resp_info); } + } + } - if (hif_drv->usr_conn_req.bssid) { - memcpy(strConnectInfo.bssid, hif_drv->usr_conn_req.bssid, 6); + if (mac_status == MAC_CONNECTED && + conn_info.status != SUCCESSFUL_STATUSCODE) { + netdev_err(vif->ndev, + "Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n"); + eth_zero_addr(wilc_connected_ssid); + } else if (mac_status == MAC_DISCONNECTED) { + netdev_err(vif->ndev, "Received MAC status is MAC_DISCONNECTED\n"); + eth_zero_addr(wilc_connected_ssid); + } - if (u8MacStatus == MAC_CONNECTED && - strConnectInfo.status == SUCCESSFUL_STATUSCODE) { - memcpy(hif_drv->assoc_bssid, - hif_drv->usr_conn_req.bssid, ETH_ALEN); - } - } + if (hif_drv->usr_conn_req.bssid) { + memcpy(conn_info.bssid, hif_drv->usr_conn_req.bssid, 6); - if (hif_drv->usr_conn_req.ies) { - strConnectInfo.req_ies_len = hif_drv->usr_conn_req.ies_len; - strConnectInfo.req_ies = kmalloc(hif_drv->usr_conn_req.ies_len, GFP_KERNEL); - memcpy(strConnectInfo.req_ies, - hif_drv->usr_conn_req.ies, - hif_drv->usr_conn_req.ies_len); - } + if (mac_status == MAC_CONNECTED && + conn_info.status == SUCCESSFUL_STATUSCODE) { + memcpy(hif_drv->assoc_bssid, + hif_drv->usr_conn_req.bssid, ETH_ALEN); + } + } - del_timer(&hif_drv->connect_timer); - hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP, - &strConnectInfo, - u8MacStatus, - NULL, - hif_drv->usr_conn_req.arg); + if (hif_drv->usr_conn_req.ies) { + conn_info.req_ies = kmemdup(conn_info.req_ies, + hif_drv->usr_conn_req.ies_len, + GFP_KERNEL); + if (conn_info.req_ies) + conn_info.req_ies_len = hif_drv->usr_conn_req.ies_len; + } - if (u8MacStatus == MAC_CONNECTED && - strConnectInfo.status == SUCCESSFUL_STATUSCODE) { - wilc_set_power_mgmt(vif, 0, 0); + del_timer(&hif_drv->connect_timer); + hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_CONN_RESP, + &conn_info, mac_status, NULL, + hif_drv->usr_conn_req.arg); - hif_drv->hif_state = HOST_IF_CONNECTED; + if (mac_status == MAC_CONNECTED && + conn_info.status == SUCCESSFUL_STATUSCODE) { + wilc_set_power_mgmt(vif, 0, 0); - wilc_optaining_ip = true; - mod_timer(&wilc_during_ip_timer, - jiffies + msecs_to_jiffies(10000)); - } else { - hif_drv->hif_state = HOST_IF_IDLE; - scan_while_connected = false; - } + hif_drv->hif_state = HOST_IF_CONNECTED; - kfree(strConnectInfo.resp_ies); - strConnectInfo.resp_ies = NULL; - - kfree(strConnectInfo.req_ies); - strConnectInfo.req_ies = NULL; - hif_drv->usr_conn_req.ssid_len = 0; - kfree(hif_drv->usr_conn_req.ssid); - hif_drv->usr_conn_req.ssid = NULL; - kfree(hif_drv->usr_conn_req.bssid); - hif_drv->usr_conn_req.bssid = NULL; - hif_drv->usr_conn_req.ies_len = 0; - kfree(hif_drv->usr_conn_req.ies); - hif_drv->usr_conn_req.ies = NULL; - } else if ((u8MacStatus == MAC_DISCONNECTED) && - (hif_drv->hif_state == HOST_IF_CONNECTED)) { - memset(&strDisconnectNotifInfo, 0, sizeof(struct disconnect_info)); + wilc_optaining_ip = true; + mod_timer(&wilc_during_ip_timer, + jiffies + msecs_to_jiffies(10000)); + } else { + hif_drv->hif_state = HOST_IF_IDLE; + scan_while_connected = false; + } - if (hif_drv->usr_scan_req.scan_result) { - del_timer(&hif_drv->scan_timer); - Handle_ScanDone(vif, SCAN_EVENT_ABORTED); - } + kfree(conn_info.resp_ies); + conn_info.resp_ies = NULL; - strDisconnectNotifInfo.reason = 0; - strDisconnectNotifInfo.ie = NULL; - strDisconnectNotifInfo.ie_len = 0; + kfree(conn_info.req_ies); + conn_info.req_ies = NULL; + host_int_free_user_conn_req(hif_drv); +} - if (hif_drv->usr_conn_req.conn_result) { - wilc_optaining_ip = false; - wilc_set_power_mgmt(vif, 0, 0); +static inline void host_int_handle_disconnect(struct wilc_vif *vif) +{ + struct disconnect_info disconn_info; + struct host_if_drv *hif_drv = vif->hif_drv; - hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, - NULL, - 0, - &strDisconnectNotifInfo, - hif_drv->usr_conn_req.arg); - } else { - netdev_err(vif->ndev, "Connect result NULL\n"); - } + memset(&disconn_info, 0, sizeof(struct disconnect_info)); - eth_zero_addr(hif_drv->assoc_bssid); + if (hif_drv->usr_scan_req.scan_result) { + del_timer(&hif_drv->scan_timer); + handle_scan_done(vif, SCAN_EVENT_ABORTED); + } - hif_drv->usr_conn_req.ssid_len = 0; - kfree(hif_drv->usr_conn_req.ssid); - hif_drv->usr_conn_req.ssid = NULL; - kfree(hif_drv->usr_conn_req.bssid); - hif_drv->usr_conn_req.bssid = NULL; - hif_drv->usr_conn_req.ies_len = 0; - kfree(hif_drv->usr_conn_req.ies); - hif_drv->usr_conn_req.ies = NULL; + disconn_info.reason = 0; + disconn_info.ie = NULL; + disconn_info.ie_len = 0; - if (join_req && join_req_vif == vif) { - kfree(join_req); - join_req = NULL; - } + if (hif_drv->usr_conn_req.conn_result) { + wilc_optaining_ip = false; + wilc_set_power_mgmt(vif, 0, 0); - if (info_element && join_req_vif == vif) { - kfree(info_element); - info_element = NULL; - } + hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, + NULL, 0, &disconn_info, + hif_drv->usr_conn_req.arg); + } else { + netdev_err(vif->ndev, "Connect result NULL\n"); + } - hif_drv->hif_state = HOST_IF_IDLE; - scan_while_connected = false; + eth_zero_addr(hif_drv->assoc_bssid); + + host_int_free_user_conn_req(hif_drv); + hif_drv->hif_state = HOST_IF_IDLE; + scan_while_connected = false; +} + +static s32 handle_rcvd_gnrl_async_info(struct wilc_vif *vif, + struct rcvd_async_info *rcvd_info) +{ + s32 result = 0; + u8 msg_type = 0; + u8 msg_id = 0; + u16 msg_len = 0; + u16 wid_id = (u16)WID_NIL; + u8 wid_len = 0; + u8 mac_status; + u8 mac_status_reason_code; + u8 mac_status_additional_info; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!rcvd_info->buffer) { + netdev_err(vif->ndev, "Received buffer is NULL\n"); + return -EINVAL; + } + + if (!hif_drv) { + netdev_err(vif->ndev, "Driver handler is NULL\n"); + kfree(rcvd_info->buffer); + rcvd_info->buffer = NULL; + return -ENODEV; + } + + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP || + hif_drv->hif_state == HOST_IF_CONNECTED || + hif_drv->usr_scan_req.scan_result) { + if (!hif_drv->usr_conn_req.conn_result) { + netdev_err(vif->ndev, "driver is null\n"); + kfree(rcvd_info->buffer); + rcvd_info->buffer = NULL; + return -EINVAL; + } + + msg_type = rcvd_info->buffer[0]; + + if ('I' != msg_type) { + netdev_err(vif->ndev, "Received Message incorrect.\n"); + kfree(rcvd_info->buffer); + rcvd_info->buffer = NULL; + return -EFAULT; + } - } else if ((u8MacStatus == MAC_DISCONNECTED) && + msg_id = rcvd_info->buffer[1]; + msg_len = MAKE_WORD16(rcvd_info->buffer[2], rcvd_info->buffer[3]); + wid_id = MAKE_WORD16(rcvd_info->buffer[4], rcvd_info->buffer[5]); + wid_len = rcvd_info->buffer[6]; + mac_status = rcvd_info->buffer[7]; + mac_status_reason_code = rcvd_info->buffer[8]; + mac_status_additional_info = rcvd_info->buffer[9]; + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { + host_int_parse_assoc_resp_info(vif, mac_status); + } else if ((mac_status == MAC_DISCONNECTED) && + (hif_drv->hif_state == HOST_IF_CONNECTED)) { + host_int_handle_disconnect(vif); + } else if ((mac_status == MAC_DISCONNECTED) && (hif_drv->usr_scan_req.scan_result)) { del_timer(&hif_drv->scan_timer); if (hif_drv->usr_scan_req.scan_result) - Handle_ScanDone(vif, SCAN_EVENT_ABORTED); + handle_scan_done(vif, SCAN_EVENT_ABORTED); } } - kfree(pstrRcvdGnrlAsyncInfo->buffer); - pstrRcvdGnrlAsyncInfo->buffer = NULL; + kfree(rcvd_info->buffer); + rcvd_info->buffer = NULL; return result; } -static int Handle_Key(struct wilc_vif *vif, - struct key_attr *pstrHostIFkeyAttr) +static int handle_key(struct wilc_vif *vif, struct key_attr *hif_key) { s32 result = 0; struct wid wid; - struct wid strWIDList[5]; + struct wid wid_list[5]; u8 i; - u8 *pu8keybuf; + u8 *key_buf; s8 s8idxarray[1]; s8 ret = 0; struct host_if_drv *hif_drv = vif->hif_drv; - switch (pstrHostIFkeyAttr->type) { + switch (hif_key->type) { case WEP: - if (pstrHostIFkeyAttr->action & ADDKEY_AP) { - strWIDList[0].id = (u16)WID_11I_MODE; - strWIDList[0].type = WID_CHAR; - strWIDList[0].size = sizeof(char); - strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.mode; + if (hif_key->action & ADDKEY_AP) { + wid_list[0].id = (u16)WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = (s8 *)&hif_key->attr.wep.mode; - strWIDList[1].id = WID_AUTH_TYPE; - strWIDList[1].type = WID_CHAR; - strWIDList[1].size = sizeof(char); - strWIDList[1].val = (s8 *)&pstrHostIFkeyAttr->attr.wep.auth_type; + wid_list[1].id = WID_AUTH_TYPE; + wid_list[1].type = WID_CHAR; + wid_list[1].size = sizeof(char); + wid_list[1].val = (s8 *)&hif_key->attr.wep.auth_type; - pu8keybuf = kmalloc(pstrHostIFkeyAttr->attr.wep.key_len + 2, - GFP_KERNEL); - if (!pu8keybuf) + key_buf = kmalloc(hif_key->attr.wep.key_len + 2, + GFP_KERNEL); + if (!key_buf) return -ENOMEM; - pu8keybuf[0] = pstrHostIFkeyAttr->attr.wep.index; - pu8keybuf[1] = pstrHostIFkeyAttr->attr.wep.key_len; + key_buf[0] = hif_key->attr.wep.index; + key_buf[1] = hif_key->attr.wep.key_len; - memcpy(&pu8keybuf[2], pstrHostIFkeyAttr->attr.wep.key, - pstrHostIFkeyAttr->attr.wep.key_len); + memcpy(&key_buf[2], hif_key->attr.wep.key, + hif_key->attr.wep.key_len); - kfree(pstrHostIFkeyAttr->attr.wep.key); + kfree(hif_key->attr.wep.key); - strWIDList[2].id = (u16)WID_WEP_KEY_VALUE; - strWIDList[2].type = WID_STR; - strWIDList[2].size = pstrHostIFkeyAttr->attr.wep.key_len + 2; - strWIDList[2].val = (s8 *)pu8keybuf; + wid_list[2].id = (u16)WID_WEP_KEY_VALUE; + wid_list[2].type = WID_STR; + wid_list[2].size = hif_key->attr.wep.key_len + 2; + wid_list[2].val = (s8 *)key_buf; result = wilc_send_config_pkt(vif, SET_CFG, - strWIDList, 3, + wid_list, 3, wilc_get_vif_idx(vif)); - kfree(pu8keybuf); - } else if (pstrHostIFkeyAttr->action & ADDKEY) { - pu8keybuf = kmalloc(pstrHostIFkeyAttr->attr.wep.key_len + 2, GFP_KERNEL); - if (!pu8keybuf) + kfree(key_buf); + } else if (hif_key->action & ADDKEY) { + key_buf = kmalloc(hif_key->attr.wep.key_len + 2, GFP_KERNEL); + if (!key_buf) return -ENOMEM; - pu8keybuf[0] = pstrHostIFkeyAttr->attr.wep.index; - memcpy(pu8keybuf + 1, &pstrHostIFkeyAttr->attr.wep.key_len, 1); - memcpy(pu8keybuf + 2, pstrHostIFkeyAttr->attr.wep.key, - pstrHostIFkeyAttr->attr.wep.key_len); - kfree(pstrHostIFkeyAttr->attr.wep.key); + key_buf[0] = hif_key->attr.wep.index; + memcpy(key_buf + 1, &hif_key->attr.wep.key_len, 1); + memcpy(key_buf + 2, hif_key->attr.wep.key, + hif_key->attr.wep.key_len); + kfree(hif_key->attr.wep.key); wid.id = (u16)WID_ADD_WEP_KEY; wid.type = WID_STR; - wid.val = (s8 *)pu8keybuf; - wid.size = pstrHostIFkeyAttr->attr.wep.key_len + 2; + wid.val = (s8 *)key_buf; + wid.size = hif_key->attr.wep.key_len + 2; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); - kfree(pu8keybuf); - } else if (pstrHostIFkeyAttr->action & REMOVEKEY) { + kfree(key_buf); + } else if (hif_key->action & REMOVEKEY) { wid.id = (u16)WID_REMOVE_WEP_KEY; wid.type = WID_STR; - s8idxarray[0] = (s8)pstrHostIFkeyAttr->attr.wep.index; + s8idxarray[0] = (s8)hif_key->attr.wep.index; wid.val = s8idxarray; wid.size = 1; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); - } else if (pstrHostIFkeyAttr->action & DEFAULTKEY) { + } else if (hif_key->action & DEFAULTKEY) { wid.id = (u16)WID_KEY_ID; wid.type = WID_CHAR; - wid.val = (s8 *)&pstrHostIFkeyAttr->attr.wep.index; + wid.val = (s8 *)&hif_key->attr.wep.index; wid.size = sizeof(char); result = wilc_send_config_pkt(vif, SET_CFG, @@ -1617,157 +1620,157 @@ static int Handle_Key(struct wilc_vif *vif, break; case WPA_RX_GTK: - if (pstrHostIFkeyAttr->action & ADDKEY_AP) { - pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL); - if (!pu8keybuf) { + if (hif_key->action & ADDKEY_AP) { + key_buf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL); + if (!key_buf) { ret = -ENOMEM; - goto _WPARxGtk_end_case_; + goto out_wpa_rx_gtk; } - if (pstrHostIFkeyAttr->attr.wpa.seq) - memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->attr.wpa.seq, 8); + if (hif_key->attr.wpa.seq) + memcpy(key_buf + 6, hif_key->attr.wpa.seq, 8); - memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->attr.wpa.index, 1); - memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); - memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->attr.wpa.key, - pstrHostIFkeyAttr->attr.wpa.key_len); + memcpy(key_buf + 14, &hif_key->attr.wpa.index, 1); + memcpy(key_buf + 15, &hif_key->attr.wpa.key_len, 1); + memcpy(key_buf + 16, hif_key->attr.wpa.key, + hif_key->attr.wpa.key_len); - strWIDList[0].id = (u16)WID_11I_MODE; - strWIDList[0].type = WID_CHAR; - strWIDList[0].size = sizeof(char); - strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode; + wid_list[0].id = (u16)WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = (s8 *)&hif_key->attr.wpa.mode; - strWIDList[1].id = (u16)WID_ADD_RX_GTK; - strWIDList[1].type = WID_STR; - strWIDList[1].val = (s8 *)pu8keybuf; - strWIDList[1].size = RX_MIC_KEY_MSG_LEN; + wid_list[1].id = (u16)WID_ADD_RX_GTK; + wid_list[1].type = WID_STR; + wid_list[1].val = (s8 *)key_buf; + wid_list[1].size = RX_MIC_KEY_MSG_LEN; result = wilc_send_config_pkt(vif, SET_CFG, - strWIDList, 2, + wid_list, 2, wilc_get_vif_idx(vif)); - kfree(pu8keybuf); + kfree(key_buf); complete(&hif_drv->comp_test_key_block); - } else if (pstrHostIFkeyAttr->action & ADDKEY) { - pu8keybuf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL); - if (!pu8keybuf) { + } else if (hif_key->action & ADDKEY) { + key_buf = kzalloc(RX_MIC_KEY_MSG_LEN, GFP_KERNEL); + if (!key_buf) { ret = -ENOMEM; - goto _WPARxGtk_end_case_; + goto out_wpa_rx_gtk; } if (hif_drv->hif_state == HOST_IF_CONNECTED) - memcpy(pu8keybuf, hif_drv->assoc_bssid, ETH_ALEN); + memcpy(key_buf, hif_drv->assoc_bssid, ETH_ALEN); else netdev_err(vif->ndev, "Couldn't handle\n"); - memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->attr.wpa.seq, 8); - memcpy(pu8keybuf + 14, &pstrHostIFkeyAttr->attr.wpa.index, 1); - memcpy(pu8keybuf + 15, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); - memcpy(pu8keybuf + 16, pstrHostIFkeyAttr->attr.wpa.key, - pstrHostIFkeyAttr->attr.wpa.key_len); + memcpy(key_buf + 6, hif_key->attr.wpa.seq, 8); + memcpy(key_buf + 14, &hif_key->attr.wpa.index, 1); + memcpy(key_buf + 15, &hif_key->attr.wpa.key_len, 1); + memcpy(key_buf + 16, hif_key->attr.wpa.key, + hif_key->attr.wpa.key_len); wid.id = (u16)WID_ADD_RX_GTK; wid.type = WID_STR; - wid.val = (s8 *)pu8keybuf; + wid.val = (s8 *)key_buf; wid.size = RX_MIC_KEY_MSG_LEN; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); - kfree(pu8keybuf); + kfree(key_buf); complete(&hif_drv->comp_test_key_block); } -_WPARxGtk_end_case_: - kfree(pstrHostIFkeyAttr->attr.wpa.key); - kfree(pstrHostIFkeyAttr->attr.wpa.seq); +out_wpa_rx_gtk: + kfree(hif_key->attr.wpa.key); + kfree(hif_key->attr.wpa.seq); if (ret) return ret; break; case WPA_PTK: - if (pstrHostIFkeyAttr->action & ADDKEY_AP) { - pu8keybuf = kmalloc(PTK_KEY_MSG_LEN + 1, GFP_KERNEL); - if (!pu8keybuf) { + if (hif_key->action & ADDKEY_AP) { + key_buf = kmalloc(PTK_KEY_MSG_LEN + 1, GFP_KERNEL); + if (!key_buf) { ret = -ENOMEM; - goto _WPAPtk_end_case_; + goto out_wpa_ptk; } - memcpy(pu8keybuf, pstrHostIFkeyAttr->attr.wpa.mac_addr, 6); - memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->attr.wpa.index, 1); - memcpy(pu8keybuf + 7, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); - memcpy(pu8keybuf + 8, pstrHostIFkeyAttr->attr.wpa.key, - pstrHostIFkeyAttr->attr.wpa.key_len); + memcpy(key_buf, hif_key->attr.wpa.mac_addr, 6); + memcpy(key_buf + 6, &hif_key->attr.wpa.index, 1); + memcpy(key_buf + 7, &hif_key->attr.wpa.key_len, 1); + memcpy(key_buf + 8, hif_key->attr.wpa.key, + hif_key->attr.wpa.key_len); - strWIDList[0].id = (u16)WID_11I_MODE; - strWIDList[0].type = WID_CHAR; - strWIDList[0].size = sizeof(char); - strWIDList[0].val = (s8 *)&pstrHostIFkeyAttr->attr.wpa.mode; + wid_list[0].id = (u16)WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = (s8 *)&hif_key->attr.wpa.mode; - strWIDList[1].id = (u16)WID_ADD_PTK; - strWIDList[1].type = WID_STR; - strWIDList[1].val = (s8 *)pu8keybuf; - strWIDList[1].size = PTK_KEY_MSG_LEN + 1; + wid_list[1].id = (u16)WID_ADD_PTK; + wid_list[1].type = WID_STR; + wid_list[1].val = (s8 *)key_buf; + wid_list[1].size = PTK_KEY_MSG_LEN + 1; result = wilc_send_config_pkt(vif, SET_CFG, - strWIDList, 2, + wid_list, 2, wilc_get_vif_idx(vif)); - kfree(pu8keybuf); + kfree(key_buf); complete(&hif_drv->comp_test_key_block); - } else if (pstrHostIFkeyAttr->action & ADDKEY) { - pu8keybuf = kmalloc(PTK_KEY_MSG_LEN, GFP_KERNEL); - if (!pu8keybuf) { + } else if (hif_key->action & ADDKEY) { + key_buf = kmalloc(PTK_KEY_MSG_LEN, GFP_KERNEL); + if (!key_buf) { netdev_err(vif->ndev, "No buffer send PTK\n"); ret = -ENOMEM; - goto _WPAPtk_end_case_; + goto out_wpa_ptk; } - memcpy(pu8keybuf, pstrHostIFkeyAttr->attr.wpa.mac_addr, 6); - memcpy(pu8keybuf + 6, &pstrHostIFkeyAttr->attr.wpa.key_len, 1); - memcpy(pu8keybuf + 7, pstrHostIFkeyAttr->attr.wpa.key, - pstrHostIFkeyAttr->attr.wpa.key_len); + memcpy(key_buf, hif_key->attr.wpa.mac_addr, 6); + memcpy(key_buf + 6, &hif_key->attr.wpa.key_len, 1); + memcpy(key_buf + 7, hif_key->attr.wpa.key, + hif_key->attr.wpa.key_len); wid.id = (u16)WID_ADD_PTK; wid.type = WID_STR; - wid.val = (s8 *)pu8keybuf; + wid.val = (s8 *)key_buf; wid.size = PTK_KEY_MSG_LEN; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); - kfree(pu8keybuf); + kfree(key_buf); complete(&hif_drv->comp_test_key_block); } -_WPAPtk_end_case_: - kfree(pstrHostIFkeyAttr->attr.wpa.key); +out_wpa_ptk: + kfree(hif_key->attr.wpa.key); if (ret) return ret; break; case PMKSA: - pu8keybuf = kmalloc((pstrHostIFkeyAttr->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1, GFP_KERNEL); - if (!pu8keybuf) + key_buf = kmalloc((hif_key->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1, GFP_KERNEL); + if (!key_buf) return -ENOMEM; - pu8keybuf[0] = pstrHostIFkeyAttr->attr.pmkid.numpmkid; + key_buf[0] = hif_key->attr.pmkid.numpmkid; - for (i = 0; i < pstrHostIFkeyAttr->attr.pmkid.numpmkid; i++) { - memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + 1), pstrHostIFkeyAttr->attr.pmkid.pmkidlist[i].bssid, ETH_ALEN); - memcpy(pu8keybuf + ((PMKSA_KEY_LEN * i) + ETH_ALEN + 1), pstrHostIFkeyAttr->attr.pmkid.pmkidlist[i].pmkid, PMKID_LEN); + for (i = 0; i < hif_key->attr.pmkid.numpmkid; i++) { + memcpy(key_buf + ((PMKSA_KEY_LEN * i) + 1), hif_key->attr.pmkid.pmkidlist[i].bssid, ETH_ALEN); + memcpy(key_buf + ((PMKSA_KEY_LEN * i) + ETH_ALEN + 1), hif_key->attr.pmkid.pmkidlist[i].pmkid, PMKID_LEN); } wid.id = (u16)WID_PMKID_INFO; wid.type = WID_STR; - wid.val = (s8 *)pu8keybuf; - wid.size = (pstrHostIFkeyAttr->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1; + wid.val = (s8 *)key_buf; + wid.size = (hif_key->attr.pmkid.numpmkid * PMKSA_KEY_LEN) + 1; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); - kfree(pu8keybuf); + kfree(key_buf); break; } @@ -1777,17 +1780,19 @@ _WPAPtk_end_case_: return result; } -static void Handle_Disconnect(struct wilc_vif *vif) +static void handle_disconnect(struct wilc_vif *vif) { struct wid wid; struct host_if_drv *hif_drv = vif->hif_drv; - + struct disconnect_info disconn_info; + struct user_scan_req *scan_req; + struct user_conn_req *conn_req; s32 result = 0; - u16 u16DummyReasonCode = 0; + u16 dummy_reason_code = 0; wid.id = (u16)WID_DISCONNECT; wid.type = WID_CHAR; - wid.val = (s8 *)&u16DummyReasonCode; + wid.val = (s8 *)&dummy_reason_code; wid.size = sizeof(char); wilc_optaining_ip = false; @@ -1800,62 +1805,50 @@ static void Handle_Disconnect(struct wilc_vif *vif) if (result) { netdev_err(vif->ndev, "Failed to send dissconect\n"); - } else { - struct disconnect_info strDisconnectNotifInfo; - - memset(&strDisconnectNotifInfo, 0, sizeof(struct disconnect_info)); + goto out; + } - strDisconnectNotifInfo.reason = 0; - strDisconnectNotifInfo.ie = NULL; - strDisconnectNotifInfo.ie_len = 0; + memset(&disconn_info, 0, sizeof(struct disconnect_info)); - if (hif_drv->usr_scan_req.scan_result) { - del_timer(&hif_drv->scan_timer); - hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, - NULL, - hif_drv->usr_scan_req.arg, - NULL); - hif_drv->usr_scan_req.scan_result = NULL; - } + disconn_info.reason = 0; + disconn_info.ie = NULL; + disconn_info.ie_len = 0; + scan_req = &hif_drv->usr_scan_req; + conn_req = &hif_drv->usr_conn_req; - if (hif_drv->usr_conn_req.conn_result) { - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) - del_timer(&hif_drv->connect_timer); + if (scan_req->scan_result) { + del_timer(&hif_drv->scan_timer); + scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg, + NULL); + scan_req->scan_result = NULL; + } - hif_drv->usr_conn_req.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, - NULL, - 0, - &strDisconnectNotifInfo, - hif_drv->usr_conn_req.arg); - } else { - netdev_err(vif->ndev, "conn_result = NULL\n"); - } + if (conn_req->conn_result) { + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) + del_timer(&hif_drv->connect_timer); - scan_while_connected = false; + conn_req->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, + 0, &disconn_info, conn_req->arg); + } else { + netdev_err(vif->ndev, "conn_result = NULL\n"); + } - hif_drv->hif_state = HOST_IF_IDLE; + scan_while_connected = false; - eth_zero_addr(hif_drv->assoc_bssid); + hif_drv->hif_state = HOST_IF_IDLE; - hif_drv->usr_conn_req.ssid_len = 0; - kfree(hif_drv->usr_conn_req.ssid); - hif_drv->usr_conn_req.ssid = NULL; - kfree(hif_drv->usr_conn_req.bssid); - hif_drv->usr_conn_req.bssid = NULL; - hif_drv->usr_conn_req.ies_len = 0; - kfree(hif_drv->usr_conn_req.ies); - hif_drv->usr_conn_req.ies = NULL; + eth_zero_addr(hif_drv->assoc_bssid); - if (join_req && join_req_vif == vif) { - kfree(join_req); - join_req = NULL; - } + conn_req->ssid_len = 0; + kfree(conn_req->ssid); + conn_req->ssid = NULL; + kfree(conn_req->bssid); + conn_req->bssid = NULL; + conn_req->ies_len = 0; + kfree(conn_req->ies); + conn_req->ies = NULL; - if (info_element && join_req_vif == vif) { - kfree(info_element); - info_element = NULL; - } - } +out: complete(&hif_drv->comp_test_disconn_block); } @@ -1869,7 +1862,7 @@ void wilc_resolve_disconnect_aberration(struct wilc_vif *vif) wilc_disconnect(vif, 1); } -static void Handle_GetRssi(struct wilc_vif *vif) +static void handle_get_rssi(struct wilc_vif *vif) { s32 result = 0; struct wid wid; @@ -1889,65 +1882,64 @@ static void Handle_GetRssi(struct wilc_vif *vif) complete(&vif->hif_drv->comp_get_rssi); } -static s32 Handle_GetStatistics(struct wilc_vif *vif, - struct rf_info *pstrStatistics) +static s32 handle_get_statistics(struct wilc_vif *vif, + struct rf_info *stats) { - struct wid strWIDList[5]; - u32 u32WidsCount = 0, result = 0; - - strWIDList[u32WidsCount].id = WID_LINKSPEED; - strWIDList[u32WidsCount].type = WID_CHAR; - strWIDList[u32WidsCount].size = sizeof(char); - strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->link_speed; - u32WidsCount++; - - strWIDList[u32WidsCount].id = WID_RSSI; - strWIDList[u32WidsCount].type = WID_CHAR; - strWIDList[u32WidsCount].size = sizeof(char); - strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rssi; - u32WidsCount++; - - strWIDList[u32WidsCount].id = WID_SUCCESS_FRAME_COUNT; - strWIDList[u32WidsCount].type = WID_INT; - strWIDList[u32WidsCount].size = sizeof(u32); - strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_cnt; - u32WidsCount++; - - strWIDList[u32WidsCount].id = WID_RECEIVED_FRAGMENT_COUNT; - strWIDList[u32WidsCount].type = WID_INT; - strWIDList[u32WidsCount].size = sizeof(u32); - strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->rx_cnt; - u32WidsCount++; - - strWIDList[u32WidsCount].id = WID_FAILED_COUNT; - strWIDList[u32WidsCount].type = WID_INT; - strWIDList[u32WidsCount].size = sizeof(u32); - strWIDList[u32WidsCount].val = (s8 *)&pstrStatistics->tx_fail_cnt; - u32WidsCount++; - - result = wilc_send_config_pkt(vif, GET_CFG, strWIDList, - u32WidsCount, + struct wid wid_list[5]; + u32 wid_cnt = 0, result = 0; + + wid_list[wid_cnt].id = WID_LINKSPEED; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&stats->link_speed; + wid_cnt++; + + wid_list[wid_cnt].id = WID_RSSI; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&stats->rssi; + wid_cnt++; + + wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt; + wid_cnt++; + + wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt; + wid_cnt++; + + wid_list[wid_cnt].id = WID_FAILED_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt; + wid_cnt++; + + result = wilc_send_config_pkt(vif, GET_CFG, wid_list, + wid_cnt, wilc_get_vif_idx(vif)); if (result) netdev_err(vif->ndev, "Failed to send scan parameters\n"); - if (pstrStatistics->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH && - pstrStatistics->link_speed != DEFAULT_LINK_SPEED) + if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH && + stats->link_speed != DEFAULT_LINK_SPEED) wilc_enable_tcp_ack_filter(true); - else if (pstrStatistics->link_speed != DEFAULT_LINK_SPEED) + else if (stats->link_speed != DEFAULT_LINK_SPEED) wilc_enable_tcp_ack_filter(false); - if (pstrStatistics != &vif->wilc->dummy_statistics) + if (stats != &vif->wilc->dummy_statistics) complete(&hif_wait_response); return 0; } -static s32 Handle_Get_InActiveTime(struct wilc_vif *vif, - struct sta_inactive_t *strHostIfStaInactiveT) +static s32 handle_get_inactive_time(struct wilc_vif *vif, + struct sta_inactive_t *hif_sta_inactive) { s32 result = 0; - u8 *stamac; struct wid wid; struct host_if_drv *hif_drv = vif->hif_drv; @@ -1958,11 +1950,11 @@ static s32 Handle_Get_InActiveTime(struct wilc_vif *vif, if (!wid.val) return -ENOMEM; - stamac = wid.val; - ether_addr_copy(stamac, strHostIfStaInactiveT->mac); + ether_addr_copy(wid.val, hif_sta_inactive->mac); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); + kfree(wid.val); if (result) { netdev_err(vif->ndev, "Failed to SET inactive time\n"); @@ -1987,64 +1979,63 @@ static s32 Handle_Get_InActiveTime(struct wilc_vif *vif, return result; } -static void Handle_AddBeacon(struct wilc_vif *vif, - struct beacon_attr *pstrSetBeaconParam) +static void handle_add_beacon(struct wilc_vif *vif, struct beacon_attr *param) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *cur_byte; wid.id = (u16)WID_ADD_BEACON; wid.type = WID_BIN; - wid.size = pstrSetBeaconParam->head_len + pstrSetBeaconParam->tail_len + 16; + wid.size = param->head_len + param->tail_len + 16; wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) - goto ERRORHANDLER; + goto error; - pu8CurrByte = wid.val; - *pu8CurrByte++ = (pstrSetBeaconParam->interval & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 8) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 16) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->interval >> 24) & 0xFF); + cur_byte = wid.val; + *cur_byte++ = (param->interval & 0xFF); + *cur_byte++ = ((param->interval >> 8) & 0xFF); + *cur_byte++ = ((param->interval >> 16) & 0xFF); + *cur_byte++ = ((param->interval >> 24) & 0xFF); - *pu8CurrByte++ = (pstrSetBeaconParam->dtim_period & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 8) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 16) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->dtim_period >> 24) & 0xFF); + *cur_byte++ = (param->dtim_period & 0xFF); + *cur_byte++ = ((param->dtim_period >> 8) & 0xFF); + *cur_byte++ = ((param->dtim_period >> 16) & 0xFF); + *cur_byte++ = ((param->dtim_period >> 24) & 0xFF); - *pu8CurrByte++ = (pstrSetBeaconParam->head_len & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 8) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 16) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->head_len >> 24) & 0xFF); + *cur_byte++ = (param->head_len & 0xFF); + *cur_byte++ = ((param->head_len >> 8) & 0xFF); + *cur_byte++ = ((param->head_len >> 16) & 0xFF); + *cur_byte++ = ((param->head_len >> 24) & 0xFF); - memcpy(pu8CurrByte, pstrSetBeaconParam->head, pstrSetBeaconParam->head_len); - pu8CurrByte += pstrSetBeaconParam->head_len; + memcpy(cur_byte, param->head, param->head_len); + cur_byte += param->head_len; - *pu8CurrByte++ = (pstrSetBeaconParam->tail_len & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 8) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 16) & 0xFF); - *pu8CurrByte++ = ((pstrSetBeaconParam->tail_len >> 24) & 0xFF); + *cur_byte++ = (param->tail_len & 0xFF); + *cur_byte++ = ((param->tail_len >> 8) & 0xFF); + *cur_byte++ = ((param->tail_len >> 16) & 0xFF); + *cur_byte++ = ((param->tail_len >> 24) & 0xFF); - if (pstrSetBeaconParam->tail) - memcpy(pu8CurrByte, pstrSetBeaconParam->tail, pstrSetBeaconParam->tail_len); - pu8CurrByte += pstrSetBeaconParam->tail_len; + if (param->tail) + memcpy(cur_byte, param->tail, param->tail_len); + cur_byte += param->tail_len; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); if (result) netdev_err(vif->ndev, "Failed to send add beacon\n"); -ERRORHANDLER: +error: kfree(wid.val); - kfree(pstrSetBeaconParam->head); - kfree(pstrSetBeaconParam->tail); + kfree(param->head); + kfree(param->tail); } -static void Handle_DelBeacon(struct wilc_vif *vif) +static void handle_del_beacon(struct wilc_vif *vif) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *cur_byte; wid.id = (u16)WID_DEL_BEACON; wid.type = WID_CHAR; @@ -2054,7 +2045,7 @@ static void Handle_DelBeacon(struct wilc_vif *vif) if (!wid.val) return; - pu8CurrByte = wid.val; + cur_byte = wid.val; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); @@ -2062,95 +2053,92 @@ static void Handle_DelBeacon(struct wilc_vif *vif) netdev_err(vif->ndev, "Failed to send delete beacon\n"); } -static u32 WILC_HostIf_PackStaParam(u8 *pu8Buffer, - struct add_sta_param *pstrStationParam) +static u32 wilc_hif_pack_sta_param(u8 *buff, struct add_sta_param *param) { - u8 *pu8CurrByte; + u8 *cur_byte; - pu8CurrByte = pu8Buffer; + cur_byte = buff; - memcpy(pu8CurrByte, pstrStationParam->bssid, ETH_ALEN); - pu8CurrByte += ETH_ALEN; + memcpy(cur_byte, param->bssid, ETH_ALEN); + cur_byte += ETH_ALEN; - *pu8CurrByte++ = pstrStationParam->aid & 0xFF; - *pu8CurrByte++ = (pstrStationParam->aid >> 8) & 0xFF; + *cur_byte++ = param->aid & 0xFF; + *cur_byte++ = (param->aid >> 8) & 0xFF; - *pu8CurrByte++ = pstrStationParam->rates_len; - if (pstrStationParam->rates_len > 0) - memcpy(pu8CurrByte, pstrStationParam->rates, - pstrStationParam->rates_len); - pu8CurrByte += pstrStationParam->rates_len; + *cur_byte++ = param->rates_len; + if (param->rates_len > 0) + memcpy(cur_byte, param->rates, param->rates_len); + cur_byte += param->rates_len; - *pu8CurrByte++ = pstrStationParam->ht_supported; - memcpy(pu8CurrByte, &pstrStationParam->ht_capa, - sizeof(struct ieee80211_ht_cap)); - pu8CurrByte += sizeof(struct ieee80211_ht_cap); + *cur_byte++ = param->ht_supported; + memcpy(cur_byte, ¶m->ht_capa, sizeof(struct ieee80211_ht_cap)); + cur_byte += sizeof(struct ieee80211_ht_cap); - *pu8CurrByte++ = pstrStationParam->flags_mask & 0xFF; - *pu8CurrByte++ = (pstrStationParam->flags_mask >> 8) & 0xFF; + *cur_byte++ = param->flags_mask & 0xFF; + *cur_byte++ = (param->flags_mask >> 8) & 0xFF; - *pu8CurrByte++ = pstrStationParam->flags_set & 0xFF; - *pu8CurrByte++ = (pstrStationParam->flags_set >> 8) & 0xFF; + *cur_byte++ = param->flags_set & 0xFF; + *cur_byte++ = (param->flags_set >> 8) & 0xFF; - return pu8CurrByte - pu8Buffer; + return cur_byte - buff; } -static void Handle_AddStation(struct wilc_vif *vif, - struct add_sta_param *pstrStationParam) +static void handle_add_station(struct wilc_vif *vif, + struct add_sta_param *param) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *cur_byte; wid.id = (u16)WID_ADD_STA; wid.type = WID_BIN; - wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->rates_len; + wid.size = WILC_ADD_STA_LENGTH + param->rates_len; wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) - goto ERRORHANDLER; + goto error; - pu8CurrByte = wid.val; - pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); + cur_byte = wid.val; + cur_byte += wilc_hif_pack_sta_param(cur_byte, param); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); if (result != 0) netdev_err(vif->ndev, "Failed to send add station\n"); -ERRORHANDLER: - kfree(pstrStationParam->rates); +error: + kfree(param->rates); kfree(wid.val); } -static void Handle_DelAllSta(struct wilc_vif *vif, - struct del_all_sta *pstrDelAllStaParam) +static void handle_del_all_sta(struct wilc_vif *vif, + struct del_all_sta *param) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *curr_byte; u8 i; - u8 au8Zero_Buff[6] = {0}; + u8 zero_buff[6] = {0}; wid.id = (u16)WID_DEL_ALL_STA; wid.type = WID_STR; - wid.size = (pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1; + wid.size = (param->assoc_sta * ETH_ALEN) + 1; - wid.val = kmalloc((pstrDelAllStaParam->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL); + wid.val = kmalloc((param->assoc_sta * ETH_ALEN) + 1, GFP_KERNEL); if (!wid.val) - goto ERRORHANDLER; + goto error; - pu8CurrByte = wid.val; + curr_byte = wid.val; - *(pu8CurrByte++) = pstrDelAllStaParam->assoc_sta; + *(curr_byte++) = param->assoc_sta; for (i = 0; i < MAX_NUM_STA; i++) { - if (memcmp(pstrDelAllStaParam->del_all_sta[i], au8Zero_Buff, ETH_ALEN)) - memcpy(pu8CurrByte, pstrDelAllStaParam->del_all_sta[i], ETH_ALEN); + if (memcmp(param->del_all_sta[i], zero_buff, ETH_ALEN)) + memcpy(curr_byte, param->del_all_sta[i], ETH_ALEN); else continue; - pu8CurrByte += ETH_ALEN; + curr_byte += ETH_ALEN; } result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, @@ -2158,18 +2146,17 @@ static void Handle_DelAllSta(struct wilc_vif *vif, if (result) netdev_err(vif->ndev, "Failed to send add station\n"); -ERRORHANDLER: +error: kfree(wid.val); complete(&hif_wait_response); } -static void Handle_DelStation(struct wilc_vif *vif, - struct del_sta *pstrDelStaParam) +static void handle_del_station(struct wilc_vif *vif, struct del_sta *param) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *cur_byte; wid.id = (u16)WID_REMOVE_STA; wid.type = WID_BIN; @@ -2177,107 +2164,108 @@ static void Handle_DelStation(struct wilc_vif *vif, wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) - goto ERRORHANDLER; + goto error; - pu8CurrByte = wid.val; + cur_byte = wid.val; - ether_addr_copy(pu8CurrByte, pstrDelStaParam->mac_addr); + ether_addr_copy(cur_byte, param->mac_addr); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); if (result) netdev_err(vif->ndev, "Failed to send add station\n"); -ERRORHANDLER: +error: kfree(wid.val); } -static void Handle_EditStation(struct wilc_vif *vif, - struct add_sta_param *pstrStationParam) +static void handle_edit_station(struct wilc_vif *vif, + struct add_sta_param *param) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *cur_byte; wid.id = (u16)WID_EDIT_STA; wid.type = WID_BIN; - wid.size = WILC_ADD_STA_LENGTH + pstrStationParam->rates_len; + wid.size = WILC_ADD_STA_LENGTH + param->rates_len; wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) - goto ERRORHANDLER; + goto error; - pu8CurrByte = wid.val; - pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); + cur_byte = wid.val; + cur_byte += wilc_hif_pack_sta_param(cur_byte, param); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); if (result) netdev_err(vif->ndev, "Failed to send edit station\n"); -ERRORHANDLER: - kfree(pstrStationParam->rates); +error: + kfree(param->rates); kfree(wid.val); } -static int Handle_RemainOnChan(struct wilc_vif *vif, - struct remain_ch *pstrHostIfRemainOnChan) +static int handle_remain_on_chan(struct wilc_vif *vif, + struct remain_ch *hif_remain_ch) { s32 result = 0; - u8 u8remain_on_chan_flag; + u8 remain_on_chan_flag; struct wid wid; struct host_if_drv *hif_drv = vif->hif_drv; if (!hif_drv->remain_on_ch_pending) { - hif_drv->remain_on_ch.arg = pstrHostIfRemainOnChan->arg; - hif_drv->remain_on_ch.expired = pstrHostIfRemainOnChan->expired; - hif_drv->remain_on_ch.ready = pstrHostIfRemainOnChan->ready; - hif_drv->remain_on_ch.ch = pstrHostIfRemainOnChan->ch; - hif_drv->remain_on_ch.id = pstrHostIfRemainOnChan->id; + hif_drv->remain_on_ch.arg = hif_remain_ch->arg; + hif_drv->remain_on_ch.expired = hif_remain_ch->expired; + hif_drv->remain_on_ch.ready = hif_remain_ch->ready; + hif_drv->remain_on_ch.ch = hif_remain_ch->ch; + hif_drv->remain_on_ch.id = hif_remain_ch->id; } else { - pstrHostIfRemainOnChan->ch = hif_drv->remain_on_ch.ch; + hif_remain_ch->ch = hif_drv->remain_on_ch.ch; } if (hif_drv->usr_scan_req.scan_result) { hif_drv->remain_on_ch_pending = 1; result = -EBUSY; - goto ERRORHANDLER; + goto error; } if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { result = -EBUSY; - goto ERRORHANDLER; + goto error; } if (wilc_optaining_ip || wilc_connecting) { result = -EBUSY; - goto ERRORHANDLER; + goto error; } - u8remain_on_chan_flag = true; + remain_on_chan_flag = true; wid.id = (u16)WID_REMAIN_ON_CHAN; wid.type = WID_STR; wid.size = 2; wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) { result = -ENOMEM; - goto ERRORHANDLER; + goto error; } - wid.val[0] = u8remain_on_chan_flag; - wid.val[1] = (s8)pstrHostIfRemainOnChan->ch; + wid.val[0] = remain_on_chan_flag; + wid.val[1] = (s8)hif_remain_ch->ch; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); + kfree(wid.val); if (result != 0) netdev_err(vif->ndev, "Failed to set remain on channel\n"); -ERRORHANDLER: +error: { P2P_LISTEN_STATE = 1; hif_drv->remain_on_ch_timer_vif = vif; mod_timer(&hif_drv->remain_on_ch_timer, jiffies + - msecs_to_jiffies(pstrHostIfRemainOnChan->duration)); + msecs_to_jiffies(hif_remain_ch->duration)); if (hif_drv->remain_on_ch.ready) hif_drv->remain_on_ch.ready(hif_drv->remain_on_ch.arg); @@ -2289,12 +2277,12 @@ ERRORHANDLER: return result; } -static int Handle_RegisterFrame(struct wilc_vif *vif, - struct reg_frame *pstrHostIfRegisterFrame) +static int handle_register_frame(struct wilc_vif *vif, + struct reg_frame *hif_reg_frame) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *cur_byte; wid.id = (u16)WID_REGISTER_FRAME; wid.type = WID_STR; @@ -2302,16 +2290,17 @@ static int Handle_RegisterFrame(struct wilc_vif *vif, if (!wid.val) return -ENOMEM; - pu8CurrByte = wid.val; + cur_byte = wid.val; - *pu8CurrByte++ = pstrHostIfRegisterFrame->reg; - *pu8CurrByte++ = pstrHostIfRegisterFrame->reg_id; - memcpy(pu8CurrByte, &pstrHostIfRegisterFrame->frame_type, sizeof(u16)); + *cur_byte++ = hif_reg_frame->reg; + *cur_byte++ = hif_reg_frame->reg_id; + memcpy(cur_byte, &hif_reg_frame->frame_type, sizeof(u16)); wid.size = sizeof(u16) + 2; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); + kfree(wid.val); if (result) { netdev_err(vif->ndev, "Failed to frame register\n"); result = -EINVAL; @@ -2320,16 +2309,16 @@ static int Handle_RegisterFrame(struct wilc_vif *vif, return result; } -static u32 Handle_ListenStateExpired(struct wilc_vif *vif, - struct remain_ch *pstrHostIfRemainOnChan) +static u32 handle_listen_state_expired(struct wilc_vif *vif, + struct remain_ch *hif_remain_ch) { - u8 u8remain_on_chan_flag; + u8 remain_on_chan_flag; struct wid wid; s32 result = 0; struct host_if_drv *hif_drv = vif->hif_drv; if (P2P_LISTEN_STATE) { - u8remain_on_chan_flag = false; + remain_on_chan_flag = false; wid.id = (u16)WID_REMAIN_ON_CHAN; wid.type = WID_STR; wid.size = 2; @@ -2338,11 +2327,12 @@ static u32 Handle_ListenStateExpired(struct wilc_vif *vif, if (!wid.val) return -ENOMEM; - wid.val[0] = u8remain_on_chan_flag; + wid.val[0] = remain_on_chan_flag; wid.val[1] = FALSE_FRMWR_CHANNEL; result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); + kfree(wid.val); if (result != 0) { netdev_err(vif->ndev, "Failed to set remain channel\n"); goto _done_; @@ -2350,7 +2340,7 @@ static u32 Handle_ListenStateExpired(struct wilc_vif *vif, if (hif_drv->remain_on_ch.expired) { hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, - pstrHostIfRemainOnChan->id); + hif_remain_ch->id); } P2P_LISTEN_STATE = 0; } else { @@ -2362,7 +2352,7 @@ _done_: return result; } -static void ListenTimerCB(struct timer_list *t) +static void listen_timer_cb(struct timer_list *t) { struct host_if_drv *hif_drv = from_timer(hif_drv, t, remain_on_ch_timer); @@ -2382,21 +2372,21 @@ static void ListenTimerCB(struct timer_list *t) netdev_err(vif->ndev, "wilc_mq_send fail\n"); } -static void Handle_PowerManagement(struct wilc_vif *vif, - struct power_mgmt_param *strPowerMgmtParam) +static void handle_power_management(struct wilc_vif *vif, + struct power_mgmt_param *pm_param) { s32 result = 0; struct wid wid; - s8 s8PowerMode; + s8 power_mode; wid.id = (u16)WID_POWER_MANAGEMENT; - if (strPowerMgmtParam->enabled) - s8PowerMode = MIN_FAST_PS; + if (pm_param->enabled) + power_mode = MIN_FAST_PS; else - s8PowerMode = NO_POWERSAVE; + power_mode = NO_POWERSAVE; - wid.val = &s8PowerMode; + wid.val = &power_mode; wid.size = sizeof(char); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, @@ -2405,41 +2395,41 @@ static void Handle_PowerManagement(struct wilc_vif *vif, netdev_err(vif->ndev, "Failed to send power management\n"); } -static void Handle_SetMulticastFilter(struct wilc_vif *vif, - struct set_multicast *strHostIfSetMulti) +static void handle_set_mcast_filter(struct wilc_vif *vif, + struct set_multicast *hif_set_mc) { s32 result = 0; struct wid wid; - u8 *pu8CurrByte; + u8 *cur_byte; wid.id = (u16)WID_SETUP_MULTICAST_FILTER; wid.type = WID_BIN; - wid.size = sizeof(struct set_multicast) + (strHostIfSetMulti->cnt * ETH_ALEN); + wid.size = sizeof(struct set_multicast) + (hif_set_mc->cnt * ETH_ALEN); wid.val = kmalloc(wid.size, GFP_KERNEL); if (!wid.val) - goto ERRORHANDLER; + goto error; - pu8CurrByte = wid.val; - *pu8CurrByte++ = (strHostIfSetMulti->enabled & 0xFF); - *pu8CurrByte++ = 0; - *pu8CurrByte++ = 0; - *pu8CurrByte++ = 0; + cur_byte = wid.val; + *cur_byte++ = (hif_set_mc->enabled & 0xFF); + *cur_byte++ = 0; + *cur_byte++ = 0; + *cur_byte++ = 0; - *pu8CurrByte++ = (strHostIfSetMulti->cnt & 0xFF); - *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 8) & 0xFF); - *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 16) & 0xFF); - *pu8CurrByte++ = ((strHostIfSetMulti->cnt >> 24) & 0xFF); + *cur_byte++ = (hif_set_mc->cnt & 0xFF); + *cur_byte++ = ((hif_set_mc->cnt >> 8) & 0xFF); + *cur_byte++ = ((hif_set_mc->cnt >> 16) & 0xFF); + *cur_byte++ = ((hif_set_mc->cnt >> 24) & 0xFF); - if ((strHostIfSetMulti->cnt) > 0) - memcpy(pu8CurrByte, wilc_multicast_mac_addr_list, - ((strHostIfSetMulti->cnt) * ETH_ALEN)); + if (hif_set_mc->cnt > 0) + memcpy(cur_byte, wilc_multicast_mac_addr_list, + ((hif_set_mc->cnt) * ETH_ALEN)); result = wilc_send_config_pkt(vif, SET_CFG, &wid, 1, wilc_get_vif_idx(vif)); if (result) netdev_err(vif->ndev, "Failed to send setup multicast\n"); -ERRORHANDLER: +error: kfree(wid.val); } @@ -2498,20 +2488,20 @@ static void host_if_work(struct work_struct *work) break; case HOST_IF_MSG_CONNECT: - Handle_Connect(msg->vif, &msg->body.con_info); + handle_connect(msg->vif, &msg->body.con_info); break; case HOST_IF_MSG_RCVD_NTWRK_INFO: - Handle_RcvdNtwrkInfo(msg->vif, &msg->body.net_info); + handle_rcvd_ntwrk_info(msg->vif, &msg->body.net_info); break; case HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO: - Handle_RcvdGnrlAsyncInfo(msg->vif, - &msg->body.async_info); + handle_rcvd_gnrl_async_info(msg->vif, + &msg->body.async_info); break; case HOST_IF_MSG_KEY: - Handle_Key(msg->vif, &msg->body.key_info); + handle_key(msg->vif, &msg->body.key_info); break; case HOST_IF_MSG_CFG_PARAMS: @@ -2523,7 +2513,7 @@ static void host_if_work(struct work_struct *work) break; case HOST_IF_MSG_DISCONNECT: - Handle_Disconnect(msg->vif); + handle_disconnect(msg->vif); break; case HOST_IF_MSG_RCVD_SCAN_COMPLETE: @@ -2532,58 +2522,58 @@ static void host_if_work(struct work_struct *work) if (!wilc_wlan_get_num_conn_ifcs(wilc)) wilc_chip_sleep_manually(wilc); - Handle_ScanDone(msg->vif, SCAN_EVENT_DONE); + handle_scan_done(msg->vif, SCAN_EVENT_DONE); if (msg->vif->hif_drv->remain_on_ch_pending) - Handle_RemainOnChan(msg->vif, - &msg->body.remain_on_ch); + handle_remain_on_chan(msg->vif, + &msg->body.remain_on_ch); break; case HOST_IF_MSG_GET_RSSI: - Handle_GetRssi(msg->vif); + handle_get_rssi(msg->vif); break; case HOST_IF_MSG_GET_STATISTICS: - Handle_GetStatistics(msg->vif, - (struct rf_info *)msg->body.data); + handle_get_statistics(msg->vif, + (struct rf_info *)msg->body.data); break; case HOST_IF_MSG_ADD_BEACON: - Handle_AddBeacon(msg->vif, &msg->body.beacon_info); + handle_add_beacon(msg->vif, &msg->body.beacon_info); break; case HOST_IF_MSG_DEL_BEACON: - Handle_DelBeacon(msg->vif); + handle_del_beacon(msg->vif); break; case HOST_IF_MSG_ADD_STATION: - Handle_AddStation(msg->vif, &msg->body.add_sta_info); + handle_add_station(msg->vif, &msg->body.add_sta_info); break; case HOST_IF_MSG_DEL_STATION: - Handle_DelStation(msg->vif, &msg->body.del_sta_info); + handle_del_station(msg->vif, &msg->body.del_sta_info); break; case HOST_IF_MSG_EDIT_STATION: - Handle_EditStation(msg->vif, &msg->body.edit_sta_info); + handle_edit_station(msg->vif, &msg->body.edit_sta_info); break; case HOST_IF_MSG_GET_INACTIVETIME: - Handle_Get_InActiveTime(msg->vif, &msg->body.mac_info); + handle_get_inactive_time(msg->vif, &msg->body.mac_info); break; case HOST_IF_MSG_SCAN_TIMER_FIRED: - Handle_ScanDone(msg->vif, SCAN_EVENT_ABORTED); + handle_scan_done(msg->vif, SCAN_EVENT_ABORTED); break; case HOST_IF_MSG_CONNECT_TIMER_FIRED: - Handle_ConnectTimeout(msg->vif); + handle_connect_timeout(msg->vif); break; case HOST_IF_MSG_POWER_MGMT: - Handle_PowerManagement(msg->vif, - &msg->body.pwr_mgmt_info); + handle_power_management(msg->vif, + &msg->body.pwr_mgmt_info); break; case HOST_IF_MSG_SET_WFIDRV_HANDLER: @@ -2610,23 +2600,23 @@ static void host_if_work(struct work_struct *work) break; case HOST_IF_MSG_REMAIN_ON_CHAN: - Handle_RemainOnChan(msg->vif, &msg->body.remain_on_ch); + handle_remain_on_chan(msg->vif, &msg->body.remain_on_ch); break; case HOST_IF_MSG_REGISTER_FRAME: - Handle_RegisterFrame(msg->vif, &msg->body.reg_frame); + handle_register_frame(msg->vif, &msg->body.reg_frame); break; case HOST_IF_MSG_LISTEN_TIMER_FIRED: - Handle_ListenStateExpired(msg->vif, &msg->body.remain_on_ch); + handle_listen_state_expired(msg->vif, &msg->body.remain_on_ch); break; case HOST_IF_MSG_SET_MULTICAST_FILTER: - Handle_SetMulticastFilter(msg->vif, &msg->body.multicast_info); + handle_set_mcast_filter(msg->vif, &msg->body.multicast_info); break; case HOST_IF_MSG_DEL_ALL_STA: - Handle_DelAllSta(msg->vif, &msg->body.del_all_sta_info); + handle_del_all_sta(msg->vif, &msg->body.del_all_sta_info); break; case HOST_IF_MSG_SET_TX_POWER: @@ -2647,7 +2637,7 @@ free_msg: complete(&hif_thread_comp); } -static void TimerCB_Scan(struct timer_list *t) +static void timer_scan_cb(struct timer_list *t) { struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer); struct wilc_vif *vif = hif_drv->scan_timer_vif; @@ -2660,7 +2650,7 @@ static void TimerCB_Scan(struct timer_list *t) wilc_enqueue_cmd(&msg); } -static void TimerCB_Connect(struct timer_list *t) +static void timer_connect_cb(struct timer_list *t) { struct host_if_drv *hif_drv = from_timer(hif_drv, t, connect_timer); @@ -2674,13 +2664,13 @@ static void TimerCB_Connect(struct timer_list *t) wilc_enqueue_cmd(&msg); } -s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *pu8StaAddress) +s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *sta_addr) { struct wid wid; wid.id = (u16)WID_REMOVE_KEY; wid.type = WID_STR; - wid.val = (s8 *)pu8StaAddress; + wid.val = (s8 *)sta_addr; wid.size = 6; return 0; @@ -2747,7 +2737,7 @@ int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index) int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, u8 index) { - int result = 0; + int result; struct host_if_msg msg; struct host_if_drv *hif_drv = vif->hif_drv; @@ -2770,17 +2760,20 @@ int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, msg.body.key_info.attr.wep.index = index; result = wilc_enqueue_cmd(&msg); - if (result) + if (result) { netdev_err(vif->ndev, "STA - WEP Key\n"); - wait_for_completion(&hif_drv->comp_test_key_block); + kfree(msg.body.key_info.attr.wep.key); + return result; + } - return result; + wait_for_completion(&hif_drv->comp_test_key_block); + return 0; } int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, u8 index, u8 mode, enum AUTHTYPE auth_type) { - int result = 0; + int result; struct host_if_msg msg; struct host_if_drv *hif_drv = vif->hif_drv; @@ -2805,20 +2798,21 @@ int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, msg.body.key_info.attr.wep.auth_type = auth_type; result = wilc_enqueue_cmd(&msg); - - if (result) + if (result) { netdev_err(vif->ndev, "AP - WEP Key\n"); - else - wait_for_completion(&hif_drv->comp_test_key_block); + kfree(msg.body.key_info.attr.wep.key); + return result; + } - return result; + wait_for_completion(&hif_drv->comp_test_key_block); + return 0; } int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, u8 mode, u8 cipher_mode, u8 index) { - int result = 0; + int result; struct host_if_msg msg; struct host_if_drv *hif_drv = vif->hif_drv; u8 key_len = ptk_key_len; @@ -2850,10 +2844,12 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, return -ENOMEM; if (rx_mic) - memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic, RX_MIC_KEY_LEN); + memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic, + RX_MIC_KEY_LEN); if (tx_mic) - memcpy(msg.body.key_info.attr.wpa.key + 24, tx_mic, TX_MIC_KEY_LEN); + memcpy(msg.body.key_info.attr.wpa.key + 24, tx_mic, + TX_MIC_KEY_LEN); msg.body.key_info.attr.wpa.key_len = key_len; msg.body.key_info.attr.wpa.mac_addr = mac_addr; @@ -2861,13 +2857,14 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, msg.vif = vif; result = wilc_enqueue_cmd(&msg); - - if (result) + if (result) { netdev_err(vif->ndev, "PTK Key\n"); - else - wait_for_completion(&hif_drv->comp_test_key_block); + kfree(msg.body.key_info.attr.wpa.key); + return result; + } - return result; + wait_for_completion(&hif_drv->comp_test_key_block); + return 0; } int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, @@ -2875,7 +2872,7 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, const u8 *rx_mic, const u8 *tx_mic, u8 mode, u8 cipher_mode) { - int result = 0; + int result; struct host_if_msg msg; struct host_if_drv *hif_drv = vif->hif_drv; u8 key_len = gtk_key_len; @@ -2914,8 +2911,10 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, msg.body.key_info.attr.wpa.key = kmemdup(rx_gtk, key_len, GFP_KERNEL); - if (!msg.body.key_info.attr.wpa.key) + if (!msg.body.key_info.attr.wpa.key) { + kfree(msg.body.key_info.attr.wpa.seq); return -ENOMEM; + } if (rx_mic) memcpy(msg.body.key_info.attr.wpa.key + 16, rx_mic, @@ -2930,12 +2929,15 @@ int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, msg.body.key_info.attr.wpa.seq_len = key_rsc_len; result = wilc_enqueue_cmd(&msg); - if (result) + if (result) { netdev_err(vif->ndev, "RX GTK\n"); - else - wait_for_completion(&hif_drv->comp_test_key_block); + kfree(msg.body.key_info.attr.wpa.seq); + kfree(msg.body.key_info.attr.wpa.key); + return result; + } - return result; + wait_for_completion(&hif_drv->comp_test_key_block); + return 0; } int wilc_set_pmkid_info(struct wilc_vif *vif, @@ -3080,27 +3082,27 @@ int wilc_disconnect(struct wilc_vif *vif, u16 reason_code) } static s32 host_int_get_assoc_res_info(struct wilc_vif *vif, - u8 *pu8AssocRespInfo, - u32 u32MaxAssocRespInfoLen, - u32 *pu32RcvdAssocRespInfoLen) + u8 *assoc_resp_info, + u32 max_assoc_resp_info_len, + u32 *rcvd_assoc_resp_info_len) { s32 result = 0; struct wid wid; wid.id = (u16)WID_ASSOC_RES_INFO; wid.type = WID_STR; - wid.val = pu8AssocRespInfo; - wid.size = u32MaxAssocRespInfoLen; + wid.val = assoc_resp_info; + wid.size = max_assoc_resp_info_len; result = wilc_send_config_pkt(vif, GET_CFG, &wid, 1, wilc_get_vif_idx(vif)); if (result) { - *pu32RcvdAssocRespInfoLen = 0; + *rcvd_assoc_resp_info_len = 0; netdev_err(vif->ndev, "Failed to send association response\n"); return -EINVAL; } - *pu32RcvdAssocRespInfoLen = wid.size; + *rcvd_assoc_resp_info_len = wid.size; return result; } @@ -3165,7 +3167,7 @@ int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode) } s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, - u32 *pu32InactiveTime) + u32 *out_val) { s32 result = 0; struct host_if_msg msg; @@ -3188,7 +3190,7 @@ s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, else wait_for_completion(&hif_drv->comp_inactive_time); - *pu32InactiveTime = inactive_time; + *out_val = inactive_time; return result; } @@ -3316,7 +3318,7 @@ int wilc_hif_set_cfg(struct wilc_vif *vif, return wilc_enqueue_cmd(&msg); } -static void GetPeriodicRSSI(struct timer_list *unused) +static void get_periodic_rssi(struct timer_list *unused) { struct wilc_vif *vif = periodic_rssi_vif; @@ -3381,13 +3383,13 @@ int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) } periodic_rssi_vif = vif; - timer_setup(&periodic_rssi, GetPeriodicRSSI, 0); + timer_setup(&periodic_rssi, get_periodic_rssi, 0); mod_timer(&periodic_rssi, jiffies + msecs_to_jiffies(5000)); } - timer_setup(&hif_drv->scan_timer, TimerCB_Scan, 0); - timer_setup(&hif_drv->connect_timer, TimerCB_Connect, 0); - timer_setup(&hif_drv->remain_on_ch_timer, ListenTimerCB, 0); + timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0); + timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0); + timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0); mutex_init(&hif_drv->cfg_values_lock); mutex_lock(&hif_drv->cfg_values_lock); @@ -3434,7 +3436,8 @@ int wilc_deinit(struct wilc_vif *vif) if (hif_drv->usr_scan_req.scan_result) { hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, - hif_drv->usr_scan_req.arg, NULL); + hif_drv->usr_scan_req.arg, + NULL); hif_drv->usr_scan_req.scan_result = NULL; } @@ -3473,7 +3476,10 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) struct host_if_drv *hif_drv = NULL; struct wilc_vif *vif; - id = ((buffer[length - 4]) | (buffer[length - 3] << 8) | (buffer[length - 2] << 16) | (buffer[length - 1] << 24)); + id = buffer[length - 4]; + id |= (buffer[length - 3] << 8); + id |= (buffer[length - 2] << 16); + id |= (buffer[length - 1] << 24); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) return; @@ -3490,12 +3496,15 @@ void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) msg.vif = vif; msg.body.net_info.len = length; - msg.body.net_info.buffer = kmalloc(length, GFP_KERNEL); - memcpy(msg.body.net_info.buffer, buffer, length); + msg.body.net_info.buffer = kmemdup(buffer, length, GFP_KERNEL); + if (!msg.body.net_info.buffer) + return; result = wilc_enqueue_cmd(&msg); - if (result) + if (result) { netdev_err(vif->ndev, "message parameters (%d)\n", result); + kfree(msg.body.net_info.buffer); + } } void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) @@ -3508,7 +3517,10 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) mutex_lock(&hif_deinit_lock); - id = ((buffer[length - 4]) | (buffer[length - 3] << 8) | (buffer[length - 2] << 16) | (buffer[length - 1] << 24)); + id = buffer[length - 4]; + id |= (buffer[length - 3] << 8); + id |= (buffer[length - 2] << 16); + id |= (buffer[length - 1] << 24); vif = wilc_get_vif_from_idx(wilc, id); if (!vif) { mutex_unlock(&hif_deinit_lock); @@ -3534,12 +3546,17 @@ void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) msg.vif = vif; msg.body.async_info.len = length; - msg.body.async_info.buffer = kmalloc(length, GFP_KERNEL); - memcpy(msg.body.async_info.buffer, buffer, length); + msg.body.async_info.buffer = kmemdup(buffer, length, GFP_KERNEL); + if (!msg.body.async_info.buffer) { + mutex_unlock(&hif_deinit_lock); + return; + } result = wilc_enqueue_cmd(&msg); - if (result) + if (result) { netdev_err(vif->ndev, "synchronous info (%d)\n", result); + kfree(msg.body.async_info.buffer); + } mutex_unlock(&hif_deinit_lock); } @@ -3552,7 +3569,10 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) struct host_if_drv *hif_drv = NULL; struct wilc_vif *vif; - id = ((buffer[length - 4]) | (buffer[length - 3] << 8) | (buffer[length - 2] << 16) | (buffer[length - 1] << 24)); + id = buffer[length - 4]; + id |= buffer[length - 3] << 8; + id |= buffer[length - 2] << 16; + id |= buffer[length - 1] << 24; vif = wilc_get_vif_from_idx(wilc, id); if (!vif) return; @@ -3673,7 +3693,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, beacon_info->head = kmemdup(head, head_len, GFP_KERNEL); if (!beacon_info->head) { result = -ENOMEM; - goto ERRORHANDLER; + goto error; } beacon_info->tail_len = tail_len; @@ -3681,7 +3701,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, beacon_info->tail = kmemdup(tail, tail_len, GFP_KERNEL); if (!beacon_info->tail) { result = -ENOMEM; - goto ERRORHANDLER; + goto error; } } else { beacon_info->tail = NULL; @@ -3691,7 +3711,7 @@ int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, if (result) netdev_err(vif->ndev, "wilc mq send fail\n"); -ERRORHANDLER: +error: if (result) { kfree(beacon_info->head); @@ -3737,8 +3757,10 @@ int wilc_add_station(struct wilc_vif *vif, struct add_sta_param *sta_param) } result = wilc_enqueue_cmd(&msg); - if (result) + if (result) { netdev_err(vif->ndev, "wilc_mq_send fail\n"); + kfree(add_sta_info->rates); + } return result; } @@ -3780,7 +3802,8 @@ int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]) for (i = 0; i < MAX_NUM_STA; i++) { if (memcmp(mac_addr[i], zero_addr, ETH_ALEN)) { - memcpy(del_all_sta_info->del_all_sta[i], mac_addr[i], ETH_ALEN); + memcpy(del_all_sta_info->del_all_sta[i], mac_addr[i], + ETH_ALEN); assoc_sta++; } } @@ -3820,8 +3843,10 @@ int wilc_edit_station(struct wilc_vif *vif, } result = wilc_enqueue_cmd(&msg); - if (result) + if (result) { netdev_err(vif->ndev, "wilc_mq_send fail\n"); + kfree(add_sta_info->rates); + } return result; } @@ -3870,152 +3895,152 @@ int wilc_setup_multicast_filter(struct wilc_vif *vif, bool enabled, return result; } -static void *host_int_ParseJoinBssParam(struct network_info *ptstrNetworkInfo) +static void *host_int_parse_join_bss_param(struct network_info *info) { - struct join_bss_param *pNewJoinBssParam = NULL; - u8 *pu8IEs; - u16 u16IEsLen; + struct join_bss_param *param = NULL; + u8 *ies; + u16 ies_len; u16 index = 0; - u8 suppRatesNo = 0; - u8 extSuppRatesNo; - u16 jumpOffset; - u8 pcipherCount; - u8 authCount; - u8 pcipherTotalCount = 0; - u8 authTotalCount = 0; + u8 rates_no = 0; + u8 ext_rates_no; + u16 offset; + u8 pcipher_cnt; + u8 auth_cnt; + u8 pcipher_total_cnt = 0; + u8 auth_total_cnt = 0; u8 i, j; - pu8IEs = ptstrNetworkInfo->ies; - u16IEsLen = ptstrNetworkInfo->ies_len; - - pNewJoinBssParam = kzalloc(sizeof(*pNewJoinBssParam), GFP_KERNEL); - if (pNewJoinBssParam) { - pNewJoinBssParam->dtim_period = ptstrNetworkInfo->dtim_period; - pNewJoinBssParam->beacon_period = ptstrNetworkInfo->beacon_period; - pNewJoinBssParam->cap_info = ptstrNetworkInfo->cap_info; - memcpy(pNewJoinBssParam->bssid, ptstrNetworkInfo->bssid, 6); - memcpy((u8 *)pNewJoinBssParam->ssid, ptstrNetworkInfo->ssid, - ptstrNetworkInfo->ssid_len + 1); - pNewJoinBssParam->ssid_len = ptstrNetworkInfo->ssid_len; - memset(pNewJoinBssParam->rsn_pcip_policy, 0xFF, 3); - memset(pNewJoinBssParam->rsn_auth_policy, 0xFF, 3); - - while (index < u16IEsLen) { - if (pu8IEs[index] == SUPP_RATES_IE) { - suppRatesNo = pu8IEs[index + 1]; - pNewJoinBssParam->supp_rates[0] = suppRatesNo; - index += 2; - - for (i = 0; i < suppRatesNo; i++) - pNewJoinBssParam->supp_rates[i + 1] = pu8IEs[index + i]; - - index += suppRatesNo; - } else if (pu8IEs[index] == EXT_SUPP_RATES_IE) { - extSuppRatesNo = pu8IEs[index + 1]; - if (extSuppRatesNo > (MAX_RATES_SUPPORTED - suppRatesNo)) - pNewJoinBssParam->supp_rates[0] = MAX_RATES_SUPPORTED; - else - pNewJoinBssParam->supp_rates[0] += extSuppRatesNo; - index += 2; - for (i = 0; i < (pNewJoinBssParam->supp_rates[0] - suppRatesNo); i++) - pNewJoinBssParam->supp_rates[suppRatesNo + i + 1] = pu8IEs[index + i]; - - index += extSuppRatesNo; - } else if (pu8IEs[index] == HT_CAPABILITY_IE) { - pNewJoinBssParam->ht_capable = true; - index += pu8IEs[index + 1] + 2; - } else if ((pu8IEs[index] == WMM_IE) && - (pu8IEs[index + 2] == 0x00) && (pu8IEs[index + 3] == 0x50) && - (pu8IEs[index + 4] == 0xF2) && - (pu8IEs[index + 5] == 0x02) && - ((pu8IEs[index + 6] == 0x00) || (pu8IEs[index + 6] == 0x01)) && - (pu8IEs[index + 7] == 0x01)) { - pNewJoinBssParam->wmm_cap = true; - - if (pu8IEs[index + 8] & BIT(7)) - pNewJoinBssParam->uapsd_cap = true; - index += pu8IEs[index + 1] + 2; - } else if ((pu8IEs[index] == P2P_IE) && - (pu8IEs[index + 2] == 0x50) && (pu8IEs[index + 3] == 0x6f) && - (pu8IEs[index + 4] == 0x9a) && - (pu8IEs[index + 5] == 0x09) && (pu8IEs[index + 6] == 0x0c)) { - u16 u16P2P_count; - - pNewJoinBssParam->tsf = ptstrNetworkInfo->tsf_lo; - pNewJoinBssParam->noa_enabled = 1; - pNewJoinBssParam->idx = pu8IEs[index + 9]; - - if (pu8IEs[index + 10] & BIT(7)) { - pNewJoinBssParam->opp_enabled = 1; - pNewJoinBssParam->ct_window = pu8IEs[index + 10]; - } else { - pNewJoinBssParam->opp_enabled = 0; - } + ies = info->ies; + ies_len = info->ies_len; - pNewJoinBssParam->cnt = pu8IEs[index + 11]; - u16P2P_count = index + 12; + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + return NULL; - memcpy(pNewJoinBssParam->duration, pu8IEs + u16P2P_count, 4); - u16P2P_count += 4; + param->dtim_period = info->dtim_period; + param->beacon_period = info->beacon_period; + param->cap_info = info->cap_info; + memcpy(param->bssid, info->bssid, 6); + memcpy((u8 *)param->ssid, info->ssid, info->ssid_len + 1); + param->ssid_len = info->ssid_len; + memset(param->rsn_pcip_policy, 0xFF, 3); + memset(param->rsn_auth_policy, 0xFF, 3); + + while (index < ies_len) { + if (ies[index] == SUPP_RATES_IE) { + rates_no = ies[index + 1]; + param->supp_rates[0] = rates_no; + index += 2; + + for (i = 0; i < rates_no; i++) + param->supp_rates[i + 1] = ies[index + i]; + + index += rates_no; + } else if (ies[index] == EXT_SUPP_RATES_IE) { + ext_rates_no = ies[index + 1]; + if (ext_rates_no > (MAX_RATES_SUPPORTED - rates_no)) + param->supp_rates[0] = MAX_RATES_SUPPORTED; + else + param->supp_rates[0] += ext_rates_no; + index += 2; + for (i = 0; i < (param->supp_rates[0] - rates_no); i++) + param->supp_rates[rates_no + i + 1] = ies[index + i]; + + index += ext_rates_no; + } else if (ies[index] == HT_CAPABILITY_IE) { + param->ht_capable = true; + index += ies[index + 1] + 2; + } else if ((ies[index] == WMM_IE) && + (ies[index + 2] == 0x00) && (ies[index + 3] == 0x50) && + (ies[index + 4] == 0xF2) && + (ies[index + 5] == 0x02) && + ((ies[index + 6] == 0x00) || (ies[index + 6] == 0x01)) && + (ies[index + 7] == 0x01)) { + param->wmm_cap = true; + + if (ies[index + 8] & BIT(7)) + param->uapsd_cap = true; + index += ies[index + 1] + 2; + } else if ((ies[index] == P2P_IE) && + (ies[index + 2] == 0x50) && (ies[index + 3] == 0x6f) && + (ies[index + 4] == 0x9a) && + (ies[index + 5] == 0x09) && (ies[index + 6] == 0x0c)) { + u16 p2p_cnt; + + param->tsf = info->tsf_lo; + param->noa_enabled = 1; + param->idx = ies[index + 9]; + + if (ies[index + 10] & BIT(7)) { + param->opp_enabled = 1; + param->ct_window = ies[index + 10]; + } else { + param->opp_enabled = 0; + } - memcpy(pNewJoinBssParam->interval, pu8IEs + u16P2P_count, 4); - u16P2P_count += 4; + param->cnt = ies[index + 11]; + p2p_cnt = index + 12; - memcpy(pNewJoinBssParam->start_time, pu8IEs + u16P2P_count, 4); + memcpy(param->duration, ies + p2p_cnt, 4); + p2p_cnt += 4; - index += pu8IEs[index + 1] + 2; - } else if ((pu8IEs[index] == RSN_IE) || - ((pu8IEs[index] == WPA_IE) && (pu8IEs[index + 2] == 0x00) && - (pu8IEs[index + 3] == 0x50) && (pu8IEs[index + 4] == 0xF2) && - (pu8IEs[index + 5] == 0x01))) { - u16 rsnIndex = index; + memcpy(param->interval, ies + p2p_cnt, 4); + p2p_cnt += 4; - if (pu8IEs[rsnIndex] == RSN_IE) { - pNewJoinBssParam->mode_802_11i = 2; - } else { - if (pNewJoinBssParam->mode_802_11i == 0) - pNewJoinBssParam->mode_802_11i = 1; - rsnIndex += 4; - } + memcpy(param->start_time, ies + p2p_cnt, 4); - rsnIndex += 7; - pNewJoinBssParam->rsn_grp_policy = pu8IEs[rsnIndex]; - rsnIndex++; - jumpOffset = pu8IEs[rsnIndex] * 4; - pcipherCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex]; - rsnIndex += 2; + index += ies[index + 1] + 2; + } else if ((ies[index] == RSN_IE) || + ((ies[index] == WPA_IE) && (ies[index + 2] == 0x00) && + (ies[index + 3] == 0x50) && (ies[index + 4] == 0xF2) && + (ies[index + 5] == 0x01))) { + u16 rsn_idx = index; - for (i = pcipherTotalCount, j = 0; i < pcipherCount + pcipherTotalCount && i < 3; i++, j++) - pNewJoinBssParam->rsn_pcip_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1]; + if (ies[rsn_idx] == RSN_IE) { + param->mode_802_11i = 2; + } else { + if (param->mode_802_11i == 0) + param->mode_802_11i = 1; + rsn_idx += 4; + } - pcipherTotalCount += pcipherCount; - rsnIndex += jumpOffset; + rsn_idx += 7; + param->rsn_grp_policy = ies[rsn_idx]; + rsn_idx++; + offset = ies[rsn_idx] * 4; + pcipher_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx]; + rsn_idx += 2; - jumpOffset = pu8IEs[rsnIndex] * 4; + for (i = pcipher_total_cnt, j = 0; i < pcipher_cnt + pcipher_total_cnt && i < 3; i++, j++) + param->rsn_pcip_policy[i] = ies[rsn_idx + ((j + 1) * 4) - 1]; - authCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex]; - rsnIndex += 2; + pcipher_total_cnt += pcipher_cnt; + rsn_idx += offset; - for (i = authTotalCount, j = 0; i < authTotalCount + authCount; i++, j++) - pNewJoinBssParam->rsn_auth_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1]; + offset = ies[rsn_idx] * 4; - authTotalCount += authCount; - rsnIndex += jumpOffset; + auth_cnt = (ies[rsn_idx] > 3) ? 3 : ies[rsn_idx]; + rsn_idx += 2; - if (pu8IEs[index] == RSN_IE) { - pNewJoinBssParam->rsn_cap[0] = pu8IEs[rsnIndex]; - pNewJoinBssParam->rsn_cap[1] = pu8IEs[rsnIndex + 1]; - rsnIndex += 2; - } - pNewJoinBssParam->rsn_found = true; - index += pu8IEs[index + 1] + 2; - } else { - index += pu8IEs[index + 1] + 2; + for (i = auth_total_cnt, j = 0; i < auth_total_cnt + auth_cnt; i++, j++) + param->rsn_auth_policy[i] = ies[rsn_idx + ((j + 1) * 4) - 1]; + + auth_total_cnt += auth_cnt; + rsn_idx += offset; + + if (ies[index] == RSN_IE) { + param->rsn_cap[0] = ies[rsn_idx]; + param->rsn_cap[1] = ies[rsn_idx + 1]; + rsn_idx += 2; } + param->rsn_found = true; + index += ies[index + 1] + 2; + } else { + index += ies[index + 1] + 2; } } - return (void *)pNewJoinBssParam; + return (void *)param; } int wilc_setup_ipaddress(struct wilc_vif *vif, u8 *ip_addr, u8 idx) diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index aa914d69ab0d..4b60b1822e91 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -304,7 +304,7 @@ struct add_sta_param { }; struct wilc_vif; -s32 wilc_remove_key(struct host_if_drv *hWFIDrv, const u8 *pu8StaAddress); +s32 wilc_remove_key(struct host_if_drv *hif_drv, const u8 *sta_addr); int wilc_remove_wep_key(struct wilc_vif *vif, u8 index); int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index); int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index 91d49c4738dc..169213f24faf 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -40,9 +40,6 @@ static u8 broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive*/ -#define IS_MANAGMEMENT 0x100 -#define IS_MANAGMEMENT_CALLBACK 0x080 -#define IS_MGMT_STATUS_SUCCES 0x040 #define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff) void WILC_WFI_monitor_rx(u8 *buff, u32 size) @@ -150,7 +147,7 @@ static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len) if (!mgmt_tx) return -ENOMEM; - mgmt_tx->buff = kmalloc(len, GFP_ATOMIC); + mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC); if (!mgmt_tx->buff) { kfree(mgmt_tx); return -ENOMEM; @@ -158,7 +155,6 @@ static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len) mgmt_tx->size = len; - memcpy(mgmt_tx->buff, buf, len); wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size, mgmt_tx_complete); @@ -256,7 +252,7 @@ static const struct net_device_ops wilc_wfi_netdev_ops = { * @brief WILC_WFI_init_mon_interface * @details * @param[in] - * @return int : Return 0 on Success + * @return Pointer to net_device * @author mdaftedar * @date 12 JUL 2012 * @version 1.0 @@ -264,7 +260,6 @@ static const struct net_device_ops wilc_wfi_netdev_ops = { struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_device *real_dev) { - u32 ret = 0; struct WILC_WFI_mon_priv *priv; /*If monitor interface is already initialized, return it*/ @@ -279,8 +274,7 @@ struct net_device *WILC_WFI_init_mon_interface(const char *name, wilc_wfi_mon->name[IFNAMSIZ - 1] = 0; wilc_wfi_mon->netdev_ops = &wilc_wfi_netdev_ops; - ret = register_netdevice(wilc_wfi_mon); - if (ret) { + if (register_netdevice(wilc_wfi_mon)) { netdev_err(real_dev, "register_netdevice failed\n"); return NULL; } diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index d9725efe0537..38a83bd31671 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -628,8 +628,7 @@ void wilc1000_wlan_deinit(struct net_device *dev) wl->hif_func->disable_interrupt(wl); mutex_unlock(&wl->hif_cs); } - if (&wl->txq_event) - complete(&wl->txq_event); + complete(&wl->txq_event); wlan_deinitialize_threads(dev); deinit_irq(dev); @@ -677,11 +676,9 @@ static int wlan_deinit_locks(struct net_device *dev) vif = netdev_priv(dev); wilc = vif->wilc; - if (&wilc->hif_cs) - mutex_destroy(&wilc->hif_cs); - - if (&wilc->rxq_cs) - mutex_destroy(&wilc->rxq_cs); + mutex_destroy(&wilc->hif_cs); + mutex_destroy(&wilc->rxq_cs); + mutex_destroy(&wilc->txq_add_to_head_cs); return 0; } @@ -716,8 +713,7 @@ static void wlan_deinitialize_threads(struct net_device *dev) wl->close = 1; - if (&wl->txq_event) - complete(&wl->txq_event); + complete(&wl->txq_event); if (wl->txq_thread) { kthread_stop(wl->txq_thread); @@ -866,10 +862,10 @@ static int wilc_mac_open(struct net_device *ndev) break; } } - wilc_get_mac_address(vif, mac_add); - netdev_dbg(ndev, "Mac address: %pM\n", mac_add); - memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN); + wilc_get_mac_address(vif, mac_add); + netdev_dbg(ndev, "Mac address: %pM\n", mac_add); + memcpy(wl->vif[i]->src_addr, mac_add, ETH_ALEN); memcpy(ndev->dev_addr, wl->vif[i]->src_addr, ETH_ALEN); if (!is_valid_ether_addr(ndev->dev_addr)) { @@ -1154,7 +1150,7 @@ void wilc_frmw_to_linux(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset) } } -void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) +void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) { int i = 0; struct wilc_vif *vif; diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index bb65b374c1ce..a08899941491 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -405,7 +405,7 @@ static int sdio_write_reg(struct wilc *wilc, u32 addr, u32 data) cmd.increment = 1; cmd.count = 4; cmd.buffer = (u8 *)&data; - cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ + cmd.block_size = g_sdio.block_size; ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) { dev_err(&func->dev, @@ -489,7 +489,7 @@ static int sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) cmd.count = nleft; cmd.buffer = buf; - cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + cmd.block_size = block_size; if (addr > 0) { if (!sdio_set_func0_csa_address(wilc, addr)) @@ -543,7 +543,7 @@ static int sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data) cmd.count = 4; cmd.buffer = (u8 *)data; - cmd.block_size = g_sdio.block_size; /* johnny : prevent it from setting unexpected value */ + cmd.block_size = g_sdio.block_size; ret = wilc_sdio_cmd53(wilc, &cmd); if (ret) { dev_err(&func->dev, @@ -629,7 +629,7 @@ static int sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) cmd.count = nleft; cmd.buffer = buf; - cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ + cmd.block_size = block_size; if (addr > 0) { if (!sdio_set_func0_csa_address(wilc, addr)) @@ -871,6 +871,7 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val) { struct sdio_func *func = dev_to_sdio_func(wilc->dev); int ret; + int vmm_ctl; if (g_sdio.has_thrpt_enh3) { u32 reg; @@ -909,84 +910,82 @@ static int sdio_clear_int_ext(struct wilc *wilc, u32 val) goto _fail_; } } - } else { - if (g_sdio.irq_gpio) { - /* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */ - /* Cannot clear multiple interrupts. Must clear each interrupt individually */ - u32 flags; - - flags = val & (BIT(MAX_NUM_INT) - 1); - if (flags) { - int i; - - ret = 1; - for (i = 0; i < g_sdio.nint; i++) { - if (flags & 1) { - struct sdio_cmd52 cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf8; - cmd.data = BIT(i); - - ret = wilc_sdio_cmd52(wilc, &cmd); - if (ret) { - dev_err(&func->dev, - "Failed cmd52, set 0xf8 data (%d) ...\n", - __LINE__); - goto _fail_; - } + return 1; + } + if (g_sdio.irq_gpio) { + /* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */ + /* + * Cannot clear multiple interrupts. + * Must clear each interrupt individually. + */ + u32 flags; + + flags = val & (BIT(MAX_NUM_INT) - 1); + if (flags) { + int i; + + ret = 1; + for (i = 0; i < g_sdio.nint; i++) { + if (flags & 1) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf8; + cmd.data = BIT(i); + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xf8 data (%d) ...\n", + __LINE__); + goto _fail_; } - if (!ret) - break; - flags >>= 1; } if (!ret) - goto _fail_; - for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { - if (flags & 1) - dev_err(&func->dev, - "Unexpected interrupt cleared %d...\n", - i); - flags >>= 1; - } + break; + flags >>= 1; } - } - - { - u32 vmm_ctl; - - vmm_ctl = 0; - /* select VMM table 0 */ - if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) - vmm_ctl |= BIT(0); - /* select VMM table 1 */ - if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) - vmm_ctl |= BIT(1); - /* enable VMM */ - if ((val & EN_VMM) == EN_VMM) - vmm_ctl |= BIT(2); - - if (vmm_ctl) { - struct sdio_cmd52 cmd; - - cmd.read_write = 1; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf6; - cmd.data = vmm_ctl; - ret = wilc_sdio_cmd52(wilc, &cmd); - if (ret) { + if (!ret) + goto _fail_; + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) dev_err(&func->dev, - "Failed cmd52, set 0xf6 data (%d) ...\n", - __LINE__); - goto _fail_; - } + "Unexpected interrupt cleared %d...\n", + i); + flags >>= 1; } } } + vmm_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + vmm_ctl |= BIT(0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + vmm_ctl |= BIT(1); + /* enable VMM */ + if ((val & EN_VMM) == EN_VMM) + vmm_ctl |= BIT(2); + + if (vmm_ctl) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf6; + cmd.data = vmm_ctl; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set 0xf6 data (%d) ...\n", + __LINE__); + goto _fail_; + } + } return 1; _fail_: return 0; diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c index 8f71a6022721..6b392c946a6f 100644 --- a/drivers/staging/wilc1000/wilc_spi.c +++ b/drivers/staging/wilc1000/wilc_spi.c @@ -287,17 +287,19 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, u8 rsp; int len = 0; int result = N_OK; + int retry; + u8 crc[2]; wb[0] = cmd; switch (cmd) { - case CMD_SINGLE_READ: /* single word (4 bytes) read */ + case CMD_SINGLE_READ: /* single word (4 bytes) read */ wb[1] = (u8)(adr >> 16); wb[2] = (u8)(adr >> 8); wb[3] = (u8)adr; len = 5; break; - case CMD_INTERNAL_READ: /* internal register read */ + case CMD_INTERNAL_READ: /* internal register read */ wb[1] = (u8)(adr >> 8); if (clockless == 1) wb[1] |= BIT(7); @@ -306,29 +308,29 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, len = 5; break; - case CMD_TERMINATE: /* termination */ + case CMD_TERMINATE: wb[1] = 0x00; wb[2] = 0x00; wb[3] = 0x00; len = 5; break; - case CMD_REPEAT: /* repeat */ + case CMD_REPEAT: wb[1] = 0x00; wb[2] = 0x00; wb[3] = 0x00; len = 5; break; - case CMD_RESET: /* reset */ + case CMD_RESET: wb[1] = 0xff; wb[2] = 0xff; wb[3] = 0xff; len = 5; break; - case CMD_DMA_WRITE: /* dma write */ - case CMD_DMA_READ: /* dma read */ + case CMD_DMA_WRITE: /* dma write */ + case CMD_DMA_READ: /* dma read */ wb[1] = (u8)(adr >> 16); wb[2] = (u8)(adr >> 8); wb[3] = (u8)adr; @@ -337,8 +339,8 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, len = 7; break; - case CMD_DMA_EXT_WRITE: /* dma extended write */ - case CMD_DMA_EXT_READ: /* dma extended read */ + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ wb[1] = (u8)(adr >> 16); wb[2] = (u8)(adr >> 8); wb[3] = (u8)adr; @@ -348,7 +350,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, len = 8; break; - case CMD_INTERNAL_WRITE: /* internal register write */ + case CMD_INTERNAL_WRITE: /* internal register write */ wb[1] = (u8)(adr >> 8); if (clockless == 1) wb[1] |= BIT(7); @@ -360,7 +362,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, len = 8; break; - case CMD_SINGLE_WRITE: /* single word write */ + case CMD_SINGLE_WRITE: /* single word write */ wb[1] = (u8)(adr >> 16); wb[2] = (u8)(adr >> 8); wb[3] = (u8)(adr); @@ -395,13 +397,12 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, cmd == CMD_REPEAT) { len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES); } else if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) { - if (!g_spi.crc_off) { - len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES - + NUM_CRC_BYTES + NUM_DUMMY_BYTES); - } else { - len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES - + NUM_DUMMY_BYTES); - } + int tmp = NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + + NUM_DUMMY_BYTES; + if (!g_spi.crc_off) + len2 = len + tmp + NUM_CRC_BYTES; + else + len2 = len + tmp; } else { len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES); } @@ -422,19 +423,13 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, return N_FAIL; } - /** + /* * Command/Control response - **/ - if (cmd == CMD_RESET || - cmd == CMD_TERMINATE || - cmd == CMD_REPEAT) { - rix++; /* skip 1 byte */ - } + */ + if (cmd == CMD_RESET || cmd == CMD_TERMINATE || cmd == CMD_REPEAT) + rix++; /* skip 1 byte */ - /* do { */ rsp = rb[rix++]; - /* if(rsp == cmd) break; */ - /* } while(&rptr[1] <= &rb[len2]); */ if (rsp != cmd) { dev_err(&spi->dev, @@ -443,9 +438,9 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, return N_FAIL; } - /** + /* * State response - **/ + */ rsp = rb[rix++]; if (rsp != 0x00) { dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", @@ -455,15 +450,15 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ || cmd == CMD_DMA_READ || cmd == CMD_DMA_EXT_READ) { - int retry; - /* u16 crc1, crc2; */ - u8 crc[2]; - /** + /* * Data Respnose header - **/ + */ retry = 100; do { - /* ensure there is room in buffer later to read data and crc */ + /* + * ensure there is room in buffer later + * to read data and crc + */ if (rix < len2) { rsp = rb[rix++]; } else { @@ -479,129 +474,134 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, "Error, data read response (%02x)\n", rsp); return N_RESET; } + } - if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) { - /** - * Read bytes - **/ - if ((rix + 3) < len2) { - b[0] = rb[rix++]; - b[1] = rb[rix++]; - b[2] = rb[rix++]; - b[3] = rb[rix++]; + if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) { + /* + * Read bytes + */ + if ((rix + 3) < len2) { + b[0] = rb[rix++]; + b[1] = rb[rix++]; + b[2] = rb[rix++]; + b[3] = rb[rix++]; + } else { + dev_err(&spi->dev, + "buffer overrun when reading data.\n"); + return N_FAIL; + } + + if (!g_spi.crc_off) { + /* + * Read Crc + */ + if ((rix + 1) < len2) { + crc[0] = rb[rix++]; + crc[1] = rb[rix++]; } else { dev_err(&spi->dev, - "buffer overrun when reading data.\n"); + "buffer overrun when reading crc.\n"); return N_FAIL; } + } + } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { + int ix; - if (!g_spi.crc_off) { - /** - * Read Crc - **/ - if ((rix + 1) < len2) { - crc[0] = rb[rix++]; - crc[1] = rb[rix++]; - } else { - dev_err(&spi->dev, "buffer overrun when reading crc.\n"); - return N_FAIL; - } - } - } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { - int ix; - - /* some data may be read in response to dummy bytes. */ - for (ix = 0; (rix < len2) && (ix < sz); ) - b[ix++] = rb[rix++]; - - sz -= ix; + /* some data may be read in response to dummy bytes. */ + for (ix = 0; (rix < len2) && (ix < sz); ) + b[ix++] = rb[rix++]; - if (sz > 0) { - int nbytes; + sz -= ix; - if (sz <= (DATA_PKT_SZ - ix)) - nbytes = sz; - else - nbytes = DATA_PKT_SZ - ix; + if (sz > 0) { + int nbytes; - /** - * Read bytes - **/ - if (wilc_spi_rx(wilc, &b[ix], nbytes)) { - dev_err(&spi->dev, "Failed data block read, bus error...\n"); - result = N_FAIL; - goto _error_; - } + if (sz <= (DATA_PKT_SZ - ix)) + nbytes = sz; + else + nbytes = DATA_PKT_SZ - ix; - /** - * Read Crc - **/ - if (!g_spi.crc_off) { - if (wilc_spi_rx(wilc, crc, 2)) { - dev_err(&spi->dev, "Failed data block crc read, bus error...\n"); - result = N_FAIL; - goto _error_; - } - } + /* + * Read bytes + */ + if (wilc_spi_rx(wilc, &b[ix], nbytes)) { + dev_err(&spi->dev, + "Failed block read, bus err\n"); + result = N_FAIL; + goto _error_; + } - ix += nbytes; - sz -= nbytes; + /* + * Read Crc + */ + if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) { + dev_err(&spi->dev, + "Failed block crc read, bus err\n"); + result = N_FAIL; + goto _error_; } - /* if any data in left unread, then read the rest using normal DMA code.*/ - while (sz > 0) { - int nbytes; - - if (sz <= DATA_PKT_SZ) - nbytes = sz; - else - nbytes = DATA_PKT_SZ; - - /** - * read data response only on the next DMA cycles not - * the first DMA since data response header is already - * handled above for the first DMA. - **/ - /** - * Data Respnose header - **/ - retry = 10; - do { - if (wilc_spi_rx(wilc, &rsp, 1)) { - dev_err(&spi->dev, "Failed data response read, bus error...\n"); - result = N_FAIL; - break; - } - if (((rsp >> 4) & 0xf) == 0xf) - break; - } while (retry--); - - if (result == N_FAIL) - break; + ix += nbytes; + sz -= nbytes; + } + + /* + * if any data in left unread, + * then read the rest using normal DMA code. + */ + while (sz > 0) { + int nbytes; - /** - * Read bytes - **/ - if (wilc_spi_rx(wilc, &b[ix], nbytes)) { - dev_err(&spi->dev, "Failed data block read, bus error...\n"); + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /* + * read data response only on the next DMA cycles not + * the first DMA since data response header is already + * handled above for the first DMA. + */ + /* + * Data Respnose header + */ + retry = 10; + do { + if (wilc_spi_rx(wilc, &rsp, 1)) { + dev_err(&spi->dev, + "Failed resp read, bus err\n"); result = N_FAIL; break; } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); - /** - * Read Crc - **/ - if (!g_spi.crc_off) { - if (wilc_spi_rx(wilc, crc, 2)) { - dev_err(&spi->dev, "Failed data block crc read, bus error...\n"); - result = N_FAIL; - break; - } - } + if (result == N_FAIL) + break; - ix += nbytes; - sz -= nbytes; + /* + * Read bytes + */ + if (wilc_spi_rx(wilc, &b[ix], nbytes)) { + dev_err(&spi->dev, + "Failed block read, bus err\n"); + result = N_FAIL; + break; } + + /* + * Read Crc + */ + if (!g_spi.crc_off && wilc_spi_rx(wilc, crc, 2)) { + dev_err(&spi->dev, + "Failed block crc read, bus err\n"); + result = N_FAIL; + break; + } + + ix += nbytes; + sz -= nbytes; } } _error_: @@ -614,11 +614,10 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) int ix, nbytes; int result = 1; u8 cmd, order, crc[2] = {0}; - /* u8 rsp; */ - /** - * Data - **/ + /* + * Data + */ ix = 0; do { if (sz <= DATA_PKT_SZ) @@ -626,9 +625,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) else nbytes = DATA_PKT_SZ; - /** - * Write command - **/ + /* + * Write command + */ cmd = 0xf0; if (ix == 0) { if (sz <= DATA_PKT_SZ) @@ -650,9 +649,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) break; } - /** - * Write data - **/ + /* + * Write data + */ if (wilc_spi_tx(wilc, &b[ix], nbytes)) { dev_err(&spi->dev, "Failed data block write, bus error...\n"); @@ -660,9 +659,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) break; } - /** - * Write Crc - **/ + /* + * Write Crc + */ if (!g_spi.crc_off) { if (wilc_spi_tx(wilc, crc, 2)) { dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); @@ -671,9 +670,9 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) } } - /** - * No need to wait for response - **/ + /* + * No need to wait for response + */ ix += nbytes; sz -= nbytes; } while (sz); @@ -733,7 +732,7 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) data = cpu_to_le32(data); if (addr < 0x30) { - /* Clockless register*/ + /* Clockless register */ cmd = CMD_INTERNAL_WRITE; clockless = 1; } @@ -751,9 +750,9 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) int result; u8 cmd = CMD_DMA_EXT_WRITE; - /** - * has to be greated than 4 - **/ + /* + * has to be greated than 4 + */ if (size <= 4) return 0; @@ -764,9 +763,9 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) return 0; } - /** - * Data - **/ + /* + * Data + */ result = spi_data_write(wilc, buf, size); if (result != N_OK) dev_err(&spi->dev, "Failed block data write...\n"); @@ -783,7 +782,7 @@ static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data) if (addr < 0x30) { /* dev_err(&spi->dev, "***** read addr %d\n\n", addr); */ - /* Clockless register*/ + /* Clockless register */ cmd = CMD_INTERNAL_READ; clockless = 1; } @@ -825,9 +824,9 @@ static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) static int _wilc_spi_deinit(struct wilc *wilc) { - /** - * TODO: - **/ + /* + * TODO: + */ return 1; } @@ -836,7 +835,6 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) struct spi_device *spi = to_spi_device(wilc->dev); u32 reg; u32 chipid; - static int isinit; if (isinit) { @@ -849,45 +847,53 @@ static int wilc_spi_init(struct wilc *wilc, bool resume) memset(&g_spi, 0, sizeof(struct wilc_spi)); - /** - * configure protocol - **/ + /* + * configure protocol + */ g_spi.crc_off = 0; - /* TODO: We can remove the CRC trials if there is a definite way to reset */ + /* + * TODO: We can remove the CRC trials if there is a definite + * way to reset + */ /* the SPI to it's initial value. */ if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®)) { - /* Read failed. Try with CRC off. This might happen when module + /* + * Read failed. Try with CRC off. This might happen when module * is removed but chip isn't reset */ g_spi.crc_off = 1; - dev_err(&spi->dev, "Failed internal read protocol with CRC on, retrying with CRC off...\n"); + dev_err(&spi->dev, + "Failed read with CRC on, retrying with CRC off\n"); if (!spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®)) { - /* Reaad failed with both CRC on and off, something went bad */ - dev_err(&spi->dev, - "Failed internal read protocol...\n"); + /* + * Read failed with both CRC on and off, + * something went bad + */ + dev_err(&spi->dev, "Failed internal read protocol\n"); return 0; } } - if (g_spi.crc_off == 0) { - reg &= ~0xc; /* disable crc checking */ + if (g_spi.crc_off == 0) { + reg &= ~0xc; /* disable crc checking */ reg &= ~0x70; reg |= (0x5 << 4); if (!spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg)) { - dev_err(&spi->dev, "[wilc spi %d]: Failed internal write protocol reg...\n", __LINE__); + dev_err(&spi->dev, + "[wilc spi %d]: Failed internal write reg\n", + __LINE__); return 0; } g_spi.crc_off = 1; } - /** - * make sure can read back chip id correctly - **/ + /* + * make sure can read back chip id correctly + */ if (!wilc_spi_read_reg(wilc, 0x1000, &chipid)) { dev_err(&spi->dev, "Fail cmd read chip id...\n"); return 0; } - /* dev_err(&spi->dev, "chipid (%08x)\n", chipid); */ g_spi.has_thrpt_enh = 1; @@ -933,45 +939,46 @@ static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status) int happened, j; u32 unknown_mask; u32 irq_flags; + int k = IRG_FLAGS_OFFSET + 5; if (g_spi.has_thrpt_enh) { ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE, int_status); - } else { - ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE, - &byte_cnt); - if (!ret) { - dev_err(&spi->dev, - "Failed read WILC_VMM_TO_HOST_SIZE ...\n"); - goto _fail_; - } - tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; + return ret; + } + ret = wilc_spi_read_reg(wilc, WILC_VMM_TO_HOST_SIZE, &byte_cnt); + if (!ret) { + dev_err(&spi->dev, + "Failed read WILC_VMM_TO_HOST_SIZE ...\n"); + goto _fail_; + } + tmp = (byte_cnt >> 2) & IRQ_DMA_WD_CNT_MASK; - j = 0; - do { - happened = 0; + j = 0; + do { + happened = 0; - wilc_spi_read_reg(wilc, 0x1a90, &irq_flags); - tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET); + wilc_spi_read_reg(wilc, 0x1a90, &irq_flags); + tmp |= ((irq_flags >> 27) << IRG_FLAGS_OFFSET); - if (g_spi.nint > 5) { - wilc_spi_read_reg(wilc, 0x1a94, - &irq_flags); - tmp |= (((irq_flags >> 0) & 0x7) << (IRG_FLAGS_OFFSET + 5)); - } + if (g_spi.nint > 5) { + wilc_spi_read_reg(wilc, 0x1a94, &irq_flags); + tmp |= (((irq_flags >> 0) & 0x7) << k); + } - unknown_mask = ~((1ul << g_spi.nint) - 1); + unknown_mask = ~((1ul << g_spi.nint) - 1); - if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) { - dev_err(&spi->dev, "Unexpected interrupt (2): j=%d, tmp=%x, mask=%x\n", j, tmp, unknown_mask); - happened = 1; - } + if ((tmp >> IRG_FLAGS_OFFSET) & unknown_mask) { + dev_err(&spi->dev, + "Unexpected interrupt(2):j=%d,tmp=%x,mask=%x\n", + j, tmp, unknown_mask); + happened = 1; + } - j++; - } while (happened); + j++; + } while (happened); - *int_status = tmp; - } + *int_status = tmp; _fail_: return ret; @@ -981,71 +988,69 @@ static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val) { struct spi_device *spi = to_spi_device(wilc->dev); int ret; + u32 flags; + u32 tbl_ctl; if (g_spi.has_thrpt_enh) { ret = spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE, val); - } else { - u32 flags; - - flags = val & (BIT(MAX_NUM_INT) - 1); - if (flags) { - int i; - - ret = 1; - for (i = 0; i < g_spi.nint; i++) { - /* No matter what you write 1 or 0, it will clear interrupt. */ - if (flags & 1) - ret = wilc_spi_write_reg(wilc, 0x10c8 + i * 4, 1); - if (!ret) - break; - flags >>= 1; - } - if (!ret) { + return ret; + } + + flags = val & (BIT(MAX_NUM_INT) - 1); + if (flags) { + int i; + + ret = 1; + for (i = 0; i < g_spi.nint; i++) { + /* + * No matter what you write 1 or 0, + * it will clear interrupt. + */ + if (flags & 1) + ret = wilc_spi_write_reg(wilc, + 0x10c8 + i * 4, 1); + if (!ret) + break; + flags >>= 1; + } + if (!ret) { + dev_err(&spi->dev, + "Failed wilc_spi_write_reg, set reg %x ...\n", + 0x10c8 + i * 4); + goto _fail_; + } + for (i = g_spi.nint; i < MAX_NUM_INT; i++) { + if (flags & 1) dev_err(&spi->dev, - "Failed wilc_spi_write_reg, set reg %x ...\n", - 0x10c8 + i * 4); - goto _fail_; - } - for (i = g_spi.nint; i < MAX_NUM_INT; i++) { - if (flags & 1) - dev_err(&spi->dev, - "Unexpected interrupt cleared %d...\n", - i); - flags >>= 1; - } + "Unexpected interrupt cleared %d...\n", + i); + flags >>= 1; } + } - { - u32 tbl_ctl; - - tbl_ctl = 0; - /* select VMM table 0 */ - if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) - tbl_ctl |= BIT(0); - /* select VMM table 1 */ - if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) - tbl_ctl |= BIT(1); + tbl_ctl = 0; + /* select VMM table 0 */ + if ((val & SEL_VMM_TBL0) == SEL_VMM_TBL0) + tbl_ctl |= BIT(0); + /* select VMM table 1 */ + if ((val & SEL_VMM_TBL1) == SEL_VMM_TBL1) + tbl_ctl |= BIT(1); - ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL, - tbl_ctl); - if (!ret) { - dev_err(&spi->dev, - "fail write reg vmm_tbl_ctl...\n"); - goto _fail_; - } + ret = wilc_spi_write_reg(wilc, WILC_VMM_TBL_CTL, tbl_ctl); + if (!ret) { + dev_err(&spi->dev, "fail write reg vmm_tbl_ctl...\n"); + goto _fail_; + } - if ((val & EN_VMM) == EN_VMM) { - /** - * enable vmm transfer. - **/ - ret = wilc_spi_write_reg(wilc, - WILC_VMM_CORE_CTL, 1); - if (!ret) { - dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n"); - goto _fail_; - } - } + if ((val & EN_VMM) == EN_VMM) { + /* + * enable vmm transfer. + */ + ret = wilc_spi_write_reg(wilc, WILC_VMM_CORE_CTL, 1); + if (!ret) { + dev_err(&spi->dev, "fail write reg vmm_core_ctl...\n"); + goto _fail_; } } _fail_: @@ -1065,9 +1070,9 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint) g_spi.nint = nint; - /** - * interrupt pin mux select - **/ + /* + * interrupt pin mux select + */ ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, ®); if (!ret) { dev_err(&spi->dev, "Failed read reg (%08x)...\n", @@ -1082,9 +1087,9 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint) return 0; } - /** - * interrupt enable - **/ + /* + * interrupt enable + */ ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, ®); if (!ret) { dev_err(&spi->dev, "Failed read reg (%08x)...\n", diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 621810d70450..730d64f2f46a 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -85,9 +85,6 @@ static const struct wiphy_wowlan_support wowlan_support = { #define TCP_ACK_FILTER_LINK_SPEED_THRESH 54 #define DEFAULT_LINK_SPEED 72 -#define IS_MANAGMEMENT 0x100 -#define IS_MANAGMEMENT_CALLBACK 0x080 -#define IS_MGMT_STATUS_SUCCES 0x040 #define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff) static struct network_info last_scanned_shadow[MAX_NUM_SCANNED_NETWORKS_SHADOW]; @@ -297,8 +294,7 @@ static void clear_duringIP(struct timer_list *unused) wilc_optaining_ip = false; } -static int is_network_in_shadow(struct network_info *pstrNetworkInfo, - void *user_void) +static int is_network_in_shadow(struct network_info *nw_info, void *user_void) { int state = -1; int i; @@ -309,7 +305,7 @@ static int is_network_in_shadow(struct network_info *pstrNetworkInfo, } else { for (i = 0; i < last_scanned_cnt; i++) { if (memcmp(last_scanned_shadow[i].bssid, - pstrNetworkInfo->bssid, 6) == 0) { + nw_info->bssid, 6) == 0) { state = i; break; } @@ -318,10 +314,10 @@ static int is_network_in_shadow(struct network_info *pstrNetworkInfo, return state; } -static void add_network_to_shadow(struct network_info *pstrNetworkInfo, - void *user_void, void *pJoinParams) +static void add_network_to_shadow(struct network_info *nw_info, + void *user_void, void *join_params) { - int ap_found = is_network_in_shadow(pstrNetworkInfo, user_void); + int ap_found = is_network_in_shadow(nw_info, user_void); u32 ap_index = 0; u8 rssi_index = 0; @@ -335,42 +331,41 @@ static void add_network_to_shadow(struct network_info *pstrNetworkInfo, ap_index = ap_found; } rssi_index = last_scanned_shadow[ap_index].rssi_history.index; - last_scanned_shadow[ap_index].rssi_history.samples[rssi_index++] = pstrNetworkInfo->rssi; + last_scanned_shadow[ap_index].rssi_history.samples[rssi_index++] = nw_info->rssi; if (rssi_index == NUM_RSSI) { rssi_index = 0; last_scanned_shadow[ap_index].rssi_history.full = true; } last_scanned_shadow[ap_index].rssi_history.index = rssi_index; - last_scanned_shadow[ap_index].rssi = pstrNetworkInfo->rssi; - last_scanned_shadow[ap_index].cap_info = pstrNetworkInfo->cap_info; - last_scanned_shadow[ap_index].ssid_len = pstrNetworkInfo->ssid_len; + last_scanned_shadow[ap_index].rssi = nw_info->rssi; + last_scanned_shadow[ap_index].cap_info = nw_info->cap_info; + last_scanned_shadow[ap_index].ssid_len = nw_info->ssid_len; memcpy(last_scanned_shadow[ap_index].ssid, - pstrNetworkInfo->ssid, pstrNetworkInfo->ssid_len); + nw_info->ssid, nw_info->ssid_len); memcpy(last_scanned_shadow[ap_index].bssid, - pstrNetworkInfo->bssid, ETH_ALEN); - last_scanned_shadow[ap_index].beacon_period = pstrNetworkInfo->beacon_period; - last_scanned_shadow[ap_index].dtim_period = pstrNetworkInfo->dtim_period; - last_scanned_shadow[ap_index].ch = pstrNetworkInfo->ch; - last_scanned_shadow[ap_index].ies_len = pstrNetworkInfo->ies_len; - last_scanned_shadow[ap_index].tsf_hi = pstrNetworkInfo->tsf_hi; + nw_info->bssid, ETH_ALEN); + last_scanned_shadow[ap_index].beacon_period = nw_info->beacon_period; + last_scanned_shadow[ap_index].dtim_period = nw_info->dtim_period; + last_scanned_shadow[ap_index].ch = nw_info->ch; + last_scanned_shadow[ap_index].ies_len = nw_info->ies_len; + last_scanned_shadow[ap_index].tsf_hi = nw_info->tsf_hi; if (ap_found != -1) kfree(last_scanned_shadow[ap_index].ies); - last_scanned_shadow[ap_index].ies = kmalloc(pstrNetworkInfo->ies_len, + last_scanned_shadow[ap_index].ies = kmalloc(nw_info->ies_len, GFP_KERNEL); memcpy(last_scanned_shadow[ap_index].ies, - pstrNetworkInfo->ies, pstrNetworkInfo->ies_len); + nw_info->ies, nw_info->ies_len); last_scanned_shadow[ap_index].time_scan = jiffies; last_scanned_shadow[ap_index].time_scan_cached = jiffies; last_scanned_shadow[ap_index].found = 1; if (ap_found != -1) kfree(last_scanned_shadow[ap_index].join_params); - last_scanned_shadow[ap_index].join_params = pJoinParams; + last_scanned_shadow[ap_index].join_params = join_params; } -static void CfgScanResult(enum scan_event scan_event, - struct network_info *network_info, - void *user_void, - void *join_params) +static void cfg_scan_result(enum scan_event scan_event, + struct network_info *network_info, + void *user_void, void *join_params) { struct wilc_priv *priv; struct wiphy *wiphy; @@ -379,91 +374,97 @@ static void CfgScanResult(enum scan_event scan_event, struct cfg80211_bss *bss = NULL; priv = user_void; - if (priv->cfg_scanning) { - if (scan_event == SCAN_EVENT_NETWORK_FOUND) { - wiphy = priv->dev->ieee80211_ptr->wiphy; + if (!priv->cfg_scanning) + return; + + if (scan_event == SCAN_EVENT_NETWORK_FOUND) { + wiphy = priv->dev->ieee80211_ptr->wiphy; + + if (!wiphy || !network_info) + return; + + if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && + (((s32)network_info->rssi * 100) < 0 || + ((s32)network_info->rssi * 100) > 100)) + return; + + s32Freq = ieee80211_channel_to_frequency((s32)network_info->ch, + NL80211_BAND_2GHZ); + channel = ieee80211_get_channel(wiphy, s32Freq); + + if (!channel) + return; - if (!wiphy) + if (network_info->new_network) { + if (priv->rcvd_ch_cnt >= MAX_NUM_SCANNED_NETWORKS) return; - if (wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && - (((s32)network_info->rssi * 100) < 0 || - ((s32)network_info->rssi * 100) > 100)) + priv->rcvd_ch_cnt++; + + add_network_to_shadow(network_info, priv, join_params); + + if (memcmp("DIRECT-", network_info->ssid, 7)) return; - if (network_info) { - s32Freq = ieee80211_channel_to_frequency((s32)network_info->ch, NL80211_BAND_2GHZ); - channel = ieee80211_get_channel(wiphy, s32Freq); - - if (!channel) - return; - - if (network_info->new_network) { - if (priv->rcvd_ch_cnt < MAX_NUM_SCANNED_NETWORKS) { - priv->rcvd_ch_cnt++; - - add_network_to_shadow(network_info, priv, join_params); - - if (!(memcmp("DIRECT-", network_info->ssid, 7))) { - bss = cfg80211_inform_bss(wiphy, - channel, - CFG80211_BSS_FTYPE_UNKNOWN, - network_info->bssid, - network_info->tsf_hi, - network_info->cap_info, - network_info->beacon_period, - (const u8 *)network_info->ies, - (size_t)network_info->ies_len, - (s32)network_info->rssi * 100, - GFP_KERNEL); - cfg80211_put_bss(wiphy, bss); - } - } - } else { - u32 i; + bss = cfg80211_inform_bss(wiphy, + channel, + CFG80211_BSS_FTYPE_UNKNOWN, + network_info->bssid, + network_info->tsf_hi, + network_info->cap_info, + network_info->beacon_period, + (const u8 *)network_info->ies, + (size_t)network_info->ies_len, + (s32)network_info->rssi * 100, + GFP_KERNEL); + cfg80211_put_bss(wiphy, bss); + } else { + u32 i; - for (i = 0; i < priv->rcvd_ch_cnt; i++) { - if (memcmp(last_scanned_shadow[i].bssid, network_info->bssid, 6) == 0) { - last_scanned_shadow[i].rssi = network_info->rssi; - last_scanned_shadow[i].time_scan = jiffies; - break; - } - } - } + for (i = 0; i < priv->rcvd_ch_cnt; i++) { + if (memcmp(last_scanned_shadow[i].bssid, + network_info->bssid, 6) == 0) + break; } - } else if (scan_event == SCAN_EVENT_DONE) { - refresh_scan(priv, false); - mutex_lock(&priv->scan_req_lock); + if (i >= priv->rcvd_ch_cnt) + return; - if (priv->scan_req) { - struct cfg80211_scan_info info = { - .aborted = false, - }; + last_scanned_shadow[i].rssi = network_info->rssi; + last_scanned_shadow[i].time_scan = jiffies; + } + } else if (scan_event == SCAN_EVENT_DONE) { + refresh_scan(priv, false); - cfg80211_scan_done(priv->scan_req, &info); - priv->rcvd_ch_cnt = 0; - priv->cfg_scanning = false; - priv->scan_req = NULL; - } - mutex_unlock(&priv->scan_req_lock); - } else if (scan_event == SCAN_EVENT_ABORTED) { - mutex_lock(&priv->scan_req_lock); + mutex_lock(&priv->scan_req_lock); - if (priv->scan_req) { - struct cfg80211_scan_info info = { - .aborted = false, - }; + if (priv->scan_req) { + struct cfg80211_scan_info info = { + .aborted = false, + }; - update_scan_time(); - refresh_scan(priv, false); + cfg80211_scan_done(priv->scan_req, &info); + priv->rcvd_ch_cnt = 0; + priv->cfg_scanning = false; + priv->scan_req = NULL; + } + mutex_unlock(&priv->scan_req_lock); + } else if (scan_event == SCAN_EVENT_ABORTED) { + mutex_lock(&priv->scan_req_lock); - cfg80211_scan_done(priv->scan_req, &info); - priv->cfg_scanning = false; - priv->scan_req = NULL; - } - mutex_unlock(&priv->scan_req_lock); + if (priv->scan_req) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + + update_scan_time(); + refresh_scan(priv, false); + + cfg80211_scan_done(priv->scan_req, &info); + priv->cfg_scanning = false; + priv->scan_req = NULL; } + mutex_unlock(&priv->scan_req_lock); } } @@ -586,8 +587,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) struct wilc_priv *priv; u32 i; s32 ret = 0; - u8 au8ScanChanList[MAX_NUM_SCANNED_NETWORKS]; - struct hidden_network strHiddenNetwork; + u8 scan_ch_list[MAX_NUM_SCANNED_NETWORKS]; + struct hidden_network hidden_ntwk; struct wilc_vif *vif; priv = wiphy_priv(wiphy); @@ -602,38 +603,38 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) priv->cfg_scanning = true; if (request->n_channels <= MAX_NUM_SCANNED_NETWORKS) { for (i = 0; i < request->n_channels; i++) - au8ScanChanList[i] = (u8)ieee80211_frequency_to_channel(request->channels[i]->center_freq); + scan_ch_list[i] = (u8)ieee80211_frequency_to_channel(request->channels[i]->center_freq); if (request->n_ssids >= 1) { - strHiddenNetwork.net_info = + hidden_ntwk.net_info = kmalloc_array(request->n_ssids, sizeof(struct hidden_network), GFP_KERNEL); - if (!strHiddenNetwork.net_info) + if (!hidden_ntwk.net_info) return -ENOMEM; - strHiddenNetwork.n_ssids = request->n_ssids; + hidden_ntwk.n_ssids = request->n_ssids; for (i = 0; i < request->n_ssids; i++) { if (request->ssids[i].ssid_len != 0) { - strHiddenNetwork.net_info[i].ssid = kmalloc(request->ssids[i].ssid_len, GFP_KERNEL); - memcpy(strHiddenNetwork.net_info[i].ssid, request->ssids[i].ssid, request->ssids[i].ssid_len); - strHiddenNetwork.net_info[i].ssid_len = request->ssids[i].ssid_len; + hidden_ntwk.net_info[i].ssid = kmalloc(request->ssids[i].ssid_len, GFP_KERNEL); + memcpy(hidden_ntwk.net_info[i].ssid, request->ssids[i].ssid, request->ssids[i].ssid_len); + hidden_ntwk.net_info[i].ssid_len = request->ssids[i].ssid_len; } else { - strHiddenNetwork.n_ssids -= 1; + hidden_ntwk.n_ssids -= 1; } } ret = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN, - au8ScanChanList, + scan_ch_list, request->n_channels, (const u8 *)request->ie, - request->ie_len, CfgScanResult, - (void *)priv, &strHiddenNetwork); + request->ie_len, cfg_scan_result, + (void *)priv, &hidden_ntwk); } else { ret = wilc_scan(vif, USER_SCAN, ACTIVE_SCAN, - au8ScanChanList, + scan_ch_list, request->n_channels, (const u8 *)request->ie, - request->ie_len, CfgScanResult, + request->ie_len, cfg_scan_result, (void *)priv, NULL); } } else { @@ -657,7 +658,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, struct wilc_priv *priv; struct host_if_drv *wfi_drv; - struct network_info *pstrNetworkInfo = NULL; + struct network_info *nw_info = NULL; struct wilc_vif *vif; wilc_connecting = 1; @@ -692,7 +693,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, } if (sel_bssi_idx < last_scanned_cnt) { - pstrNetworkInfo = &last_scanned_shadow[sel_bssi_idx]; + nw_info = &last_scanned_shadow[sel_bssi_idx]; } else { ret = -ENOENT; wilc_connecting = 0; @@ -775,29 +776,23 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, } if (sme->crypto.n_akm_suites) { - switch (sme->crypto.akm_suites[0]) { - case WLAN_AKM_SUITE_8021X: + if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X) auth_type = IEEE8021; - break; - - default: - break; - } } - curr_channel = pstrNetworkInfo->ch; + curr_channel = nw_info->ch; if (!wfi_drv->p2p_connect) - wlan_channel = pstrNetworkInfo->ch; + wlan_channel = nw_info->ch; - wilc_wlan_set_bssid(dev, pstrNetworkInfo->bssid, STATION_MODE); + wilc_wlan_set_bssid(dev, nw_info->bssid, STATION_MODE); - ret = wilc_set_join_req(vif, pstrNetworkInfo->bssid, sme->ssid, + ret = wilc_set_join_req(vif, nw_info->bssid, sme->ssid, sme->ssid_len, sme->ie, sme->ie_len, cfg_connect_result, (void *)priv, u8security, auth_type, - pstrNetworkInfo->ch, - pstrNetworkInfo->join_params); + nw_info->ch, + nw_info->join_params); if (ret != 0) { netdev_err(dev, "wilc_set_join_req(): Error\n"); ret = -ENOENT; @@ -959,18 +954,14 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, } kfree(priv->wilc_ptk[key_index]->key); - priv->wilc_ptk[key_index]->key = kmalloc(params->key_len, GFP_KERNEL); + memcpy(priv->wilc_ptk[key_index]->key, params->key, params->key_len); kfree(priv->wilc_ptk[key_index]->seq); - - if (params->seq_len > 0) + if (params->seq_len > 0) { priv->wilc_ptk[key_index]->seq = kmalloc(params->seq_len, GFP_KERNEL); - - memcpy(priv->wilc_ptk[key_index]->key, params->key, params->key_len); - - if (params->seq_len > 0) memcpy(priv->wilc_ptk[key_index]->seq, params->seq, params->seq_len); + } priv->wilc_ptk[key_index]->cipher = params->cipher; priv->wilc_ptk[key_index]->key_len = params->key_len; @@ -1127,8 +1118,8 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev, } static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, - bool pairwise, - const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *)) + bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params *)) { struct wilc_priv *priv; struct key_params key_params; @@ -1154,8 +1145,8 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, return 0; } -static int set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, - bool unicast, bool multicast) +static int set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool unicast, bool multicast) { struct wilc_priv *priv; struct wilc_vif *vif; @@ -1346,10 +1337,33 @@ static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) return 0; } +static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u8 ch_list_attr_idx, + u8 op_ch_attr_idx) +{ + int i = 0; + int j = 0; + + if (ch_list_attr_idx) { + u8 limit = ch_list_attr_idx + 3 + buf[ch_list_attr_idx + 1]; + + for (i = ch_list_attr_idx + 3; i < limit; i++) { + if (buf[i] == 0x51) { + for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) + buf[j] = wlan_channel; + break; + } + } + } + + if (op_ch_attr_idx) { + buf[op_ch_attr_idx + 6] = 0x51; + buf[op_ch_attr_idx + 7] = wlan_channel; + } +} + static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len) { u32 index = 0; - u32 i = 0, j = 0; u8 op_channel_attr_index = 0; u8 channel_list_attr_index = 0; @@ -1364,28 +1378,15 @@ static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len) op_channel_attr_index = index; index += buf[index + 1] + 3; } - if (wlan_channel != INVALID_CHANNEL) { - if (channel_list_attr_index) { - for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) { - if (buf[i] == 0x51) { - for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) - buf[j] = wlan_channel; - break; - } - } - } - - if (op_channel_attr_index) { - buf[op_channel_attr_index + 6] = 0x51; - buf[op_channel_attr_index + 7] = wlan_channel; - } - } + if (wlan_channel != INVALID_CHANNEL) + wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index, + op_channel_attr_index); } -static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch, u8 iftype) +static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch, + u8 iftype) { u32 index = 0; - u32 i = 0, j = 0; u8 op_channel_attr_index = 0; u8 channel_list_attr_index = 0; @@ -1403,22 +1404,9 @@ static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch, u8 ifty op_channel_attr_index = index; index += buf[index + 1] + 3; } - if (wlan_channel != INVALID_CHANNEL && oper_ch) { - if (channel_list_attr_index) { - for (i = channel_list_attr_index + 3; i < ((channel_list_attr_index + 3) + buf[channel_list_attr_index + 1]); i++) { - if (buf[i] == 0x51) { - for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) - buf[j] = wlan_channel; - break; - } - } - } - - if (op_channel_attr_index) { - buf[op_channel_attr_index + 6] = 0x51; - buf[op_channel_attr_index + 7] = wlan_channel; - } - } + if (wlan_channel != INVALID_CHANNEL && oper_ch) + wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index, + op_channel_attr_index); } void WILC_WFI_p2p_rx(struct net_device *dev, u8 *buff, u32 size) @@ -1717,9 +1705,13 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy, wfi_drv->p2p_timeout = jiffies; if (!priv->p2p_listen_state) { + struct wilc_wfi_p2p_listen_params *params; + + params = &priv->remain_on_ch_params; + cfg80211_remain_on_channel_expired(priv->wdev, - priv->remain_on_ch_params.listen_cookie, - priv->remain_on_ch_params.listen_ch, + params->listen_cookie, + params->listen_ch, GFP_KERNEL); } @@ -1813,7 +1805,8 @@ static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, } static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, - enum nl80211_iftype type, struct vif_params *params) + enum nl80211_iftype type, + struct vif_params *params) { struct wilc_priv *priv; struct wilc_vif *vif; @@ -1837,7 +1830,8 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, vif->iftype = STATION_MODE; wilc_set_operation_mode(vif, STATION_MODE); - memset(priv->assoc_stainfo.sta_associated_bss, 0, MAX_NUM_STA * ETH_ALEN); + memset(priv->assoc_stainfo.sta_associated_bss, 0, + MAX_NUM_STA * ETH_ALEN); wilc_enable_ps = true; wilc_set_power_mgmt(vif, 1, 0); @@ -2310,6 +2304,7 @@ int wilc_deinit_host_int(struct net_device *net) op_ifcs--; + mutex_destroy(&priv->scan_req_lock); ret = wilc_deinit(vif); clear_shadow_scan(); diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index 3337fb26c8e2..d62c4f1cddc6 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -230,7 +230,7 @@ void wilc_netdev_cleanup(struct wilc *wilc); int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type, int gpio, const struct wilc_hif_func *ops); void wilc1000_wlan_deinit(struct net_device *dev); -void WILC_WFI_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size); +void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size); int wilc_wlan_get_firmware(struct net_device *dev); int wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode); diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index acaeafc2c350..bcbb92323a0a 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -173,11 +173,13 @@ static inline int update_tcp_session(u32 index, u32 ack) static inline int add_tcp_pending_ack(u32 ack, u32 session_index, struct txq_entry_t *txqe) { - if (pending_base + pending_acks < MAX_PENDING_ACKS) { - pending_acks_info[pending_base + pending_acks].ack_num = ack; - pending_acks_info[pending_base + pending_acks].txqe = txqe; - pending_acks_info[pending_base + pending_acks].session_index = session_index; - txqe->tcp_pending_ack_idx = pending_base + pending_acks; + u32 i = pending_base + pending_acks; + + if (i < MAX_PENDING_ACKS) { + pending_acks_info[i].ack_num = ack; + pending_acks_info[i].txqe = txqe; + pending_acks_info[i].session_index = session_index; + txqe->tcp_pending_ack_idx = i; pending_acks++; } return 0; @@ -230,8 +232,10 @@ static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe) (u32)tcp_hdr_ptr[11]; for (i = 0; i < tcp_session; i++) { + u32 j = ack_session_info[i].seq_num; + if (i < 2 * MAX_TCP_SESSION && - ack_session_info[i].seq_num == seq_no) { + j == seq_no) { update_tcp_session(i, ack_no); break; } @@ -258,10 +262,20 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) spin_lock_irqsave(&wilc->txq_spinlock, wilc->txq_spinlock_flags); for (i = pending_base; i < (pending_base + pending_acks); i++) { - if (i >= MAX_PENDING_ACKS || - pending_acks_info[i].session_index >= 2 * MAX_TCP_SESSION) + u32 session_index; + u32 bigger_ack_num; + + if (i >= MAX_PENDING_ACKS) break; - if (pending_acks_info[i].ack_num < ack_session_info[pending_acks_info[i].session_index].bigger_ack_num) { + + session_index = pending_acks_info[i].session_index; + + if (session_index >= 2 * MAX_TCP_SESSION) + break; + + bigger_ack_num = ack_session_info[session_index].bigger_ack_num; + + if (pending_acks_info[i].ack_num < bigger_ack_num) { struct txq_entry_t *tqe; tqe = pending_acks_info[i].txqe; @@ -562,197 +576,196 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) u32 vmm_table[WILC_VMM_TBL_SIZE]; struct wilc_vif *vif; struct wilc *wilc; + const struct wilc_hif_func *func; vif = netdev_priv(dev); wilc = vif->wilc; txb = wilc->tx_buffer; wilc->txq_exit = 0; + + if (wilc->quit) + goto out; + + mutex_lock(&wilc->txq_add_to_head_cs); + wilc_wlan_txq_filter_dup_tcp_ack(dev); + tqe = wilc_wlan_txq_get_first(wilc); + i = 0; + sum = 0; do { - if (wilc->quit) - break; + if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) { + if (tqe->type == WILC_CFG_PKT) + vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; - mutex_lock(&wilc->txq_add_to_head_cs); - wilc_wlan_txq_filter_dup_tcp_ack(dev); - tqe = wilc_wlan_txq_get_first(wilc); - i = 0; - sum = 0; - do { - if (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) { - if (tqe->type == WILC_CFG_PKT) - vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; + else if (tqe->type == WILC_NET_PKT) + vmm_sz = ETH_ETHERNET_HDR_OFFSET; + + else + vmm_sz = HOST_HDR_OFFSET; + + vmm_sz += tqe->buffer_size; + + if (vmm_sz & 0x3) + vmm_sz = (vmm_sz + 4) & ~0x3; - else if (tqe->type == WILC_NET_PKT) - vmm_sz = ETH_ETHERNET_HDR_OFFSET; + if ((sum + vmm_sz) > LINUX_TX_SIZE) + break; - else - vmm_sz = HOST_HDR_OFFSET; + vmm_table[i] = vmm_sz / 4; + if (tqe->type == WILC_CFG_PKT) + vmm_table[i] |= BIT(10); + vmm_table[i] = cpu_to_le32(vmm_table[i]); - vmm_sz += tqe->buffer_size; + i++; + sum += vmm_sz; + tqe = wilc_wlan_txq_get_next(wilc, tqe); + } else { + break; + } + } while (1); + + if (i == 0) + goto out; + vmm_table[i] = 0x0; + + acquire_bus(wilc, ACQUIRE_AND_WAKEUP); + counter = 0; + func = wilc->hif_func; + do { + ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); + if (!ret) + break; - if (vmm_sz & 0x3) - vmm_sz = (vmm_sz + 4) & ~0x3; + if ((reg & 0x1) == 0) + break; - if ((sum + vmm_sz) > LINUX_TX_SIZE) - break; + counter++; + if (counter > 200) { + counter = 0; + ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0); + break; + } + } while (!wilc->quit); - vmm_table[i] = vmm_sz / 4; - if (tqe->type == WILC_CFG_PKT) - vmm_table[i] |= BIT(10); - vmm_table[i] = cpu_to_le32(vmm_table[i]); + if (!ret) + goto out_release_bus; - i++; - sum += vmm_sz; - tqe = wilc_wlan_txq_get_next(wilc, tqe); - } else { - break; - } - } while (1); + timeout = 200; + do { + ret = func->hif_block_tx(wilc, + WILC_VMM_TBL_RX_SHADOW_BASE, + (u8 *)vmm_table, + ((i + 1) * 4)); + if (!ret) + break; - if (i == 0) + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); + if (!ret) break; - vmm_table[i] = 0x0; - acquire_bus(wilc, ACQUIRE_AND_WAKEUP); - counter = 0; do { - ret = wilc->hif_func->hif_read_reg(wilc, - WILC_HOST_TX_CTRL, - ®); + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); if (!ret) break; - - if ((reg & 0x1) == 0) - break; - - counter++; - if (counter > 200) { - counter = 0; - ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0); + if ((reg >> 2) & 0x1) { + entries = ((reg >> 3) & 0x3f); break; } - } while (!wilc->quit); + release_bus(wilc, RELEASE_ALLOW_SLEEP); + } while (--timeout); + if (timeout <= 0) { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); + break; + } if (!ret) - goto _end_; + break; - timeout = 200; - do { - ret = wilc->hif_func->hif_block_tx(wilc, WILC_VMM_TBL_RX_SHADOW_BASE, (u8 *)vmm_table, ((i + 1) * 4)); + if (entries == 0) { + ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); if (!ret) break; - - ret = wilc->hif_func->hif_write_reg(wilc, - WILC_HOST_VMM_CTL, - 0x2); + reg &= ~BIT(0); + ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg); if (!ret) break; + break; + } + break; + } while (1); - do { - ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); - if (!ret) - break; - if ((reg >> 2) & 0x1) { - entries = ((reg >> 3) & 0x3f); - break; - } - release_bus(wilc, RELEASE_ALLOW_SLEEP); - } while (--timeout); - if (timeout <= 0) { - ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); - break; - } + if (!ret) + goto out_release_bus; - if (!ret) - break; + if (entries == 0) { + ret = WILC_TX_ERR_NO_BUF; + goto out_release_bus; + } - if (entries == 0) { - ret = wilc->hif_func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); - if (!ret) - break; - reg &= ~BIT(0); - ret = wilc->hif_func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg); - if (!ret) - break; - break; - } + release_bus(wilc, RELEASE_ALLOW_SLEEP); + + offset = 0; + i = 0; + do { + u32 header, buffer_offset; + char *bssid; + + tqe = wilc_wlan_txq_remove_from_head(dev); + if (!tqe) break; - } while (1); - if (!ret) - goto _end_; + if (vmm_table[i] == 0) + break; - if (entries == 0) { - ret = WILC_TX_ERR_NO_BUF; - goto _end_; - } + vmm_table[i] = cpu_to_le32(vmm_table[i]); + vmm_sz = (vmm_table[i] & 0x3ff); + vmm_sz *= 4; + header = (tqe->type << 31) | + (tqe->buffer_size << 15) | + vmm_sz; + if (tqe->type == WILC_MGMT_PKT) + header |= BIT(30); + else + header &= ~BIT(30); - release_bus(wilc, RELEASE_ALLOW_SLEEP); + header = cpu_to_le32(header); + memcpy(&txb[offset], &header, 4); + if (tqe->type == WILC_CFG_PKT) { + buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; + } else if (tqe->type == WILC_NET_PKT) { + bssid = ((struct tx_complete_data *)(tqe->priv))->bssid; - offset = 0; - i = 0; - do { - tqe = wilc_wlan_txq_remove_from_head(dev); - if (tqe && vmm_table[i] != 0) { - u32 header, buffer_offset; - - vmm_table[i] = cpu_to_le32(vmm_table[i]); - vmm_sz = (vmm_table[i] & 0x3ff); - vmm_sz *= 4; - header = (tqe->type << 31) | - (tqe->buffer_size << 15) | - vmm_sz; - if (tqe->type == WILC_MGMT_PKT) - header |= BIT(30); - else - header &= ~BIT(30); - - header = cpu_to_le32(header); - memcpy(&txb[offset], &header, 4); - if (tqe->type == WILC_CFG_PKT) { - buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; - } else if (tqe->type == WILC_NET_PKT) { - char *bssid = ((struct tx_complete_data *)(tqe->priv))->bssid; - - buffer_offset = ETH_ETHERNET_HDR_OFFSET; - memcpy(&txb[offset + 8], bssid, 6); - } else { - buffer_offset = HOST_HDR_OFFSET; - } + buffer_offset = ETH_ETHERNET_HDR_OFFSET; + memcpy(&txb[offset + 8], bssid, 6); + } else { + buffer_offset = HOST_HDR_OFFSET; + } - memcpy(&txb[offset + buffer_offset], - tqe->buffer, tqe->buffer_size); - offset += vmm_sz; - i++; - tqe->status = 1; - if (tqe->tx_complete_func) - tqe->tx_complete_func(tqe->priv, - tqe->status); - if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK && - tqe->tcp_pending_ack_idx < MAX_PENDING_ACKS) - pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL; - kfree(tqe); - } else { - break; - } - } while (--entries); + memcpy(&txb[offset + buffer_offset], + tqe->buffer, tqe->buffer_size); + offset += vmm_sz; + i++; + tqe->status = 1; + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, tqe->status); + if (tqe->tcp_pending_ack_idx != NOT_TCP_ACK && + tqe->tcp_pending_ack_idx < MAX_PENDING_ACKS) + pending_acks_info[tqe->tcp_pending_ack_idx].txqe = NULL; + kfree(tqe); + } while (--entries); - acquire_bus(wilc, ACQUIRE_AND_WAKEUP); + acquire_bus(wilc, ACQUIRE_AND_WAKEUP); - ret = wilc->hif_func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); - if (!ret) - goto _end_; + ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); + if (!ret) + goto out_release_bus; - ret = wilc->hif_func->hif_block_tx_ext(wilc, 0, txb, offset); - if (!ret) - goto _end_; + ret = func->hif_block_tx_ext(wilc, 0, txb, offset); -_end_: +out_release_bus: + release_bus(wilc, RELEASE_ALLOW_SLEEP); - release_bus(wilc, RELEASE_ALLOW_SLEEP); - if (ret != 1) - break; - } while (0); +out: mutex_unlock(&wilc->txq_add_to_head_cs); wilc->txq_exit = 1; @@ -760,9 +773,70 @@ _end_: return ret; } +static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size) +{ + int offset = 0; + u32 header; + u32 pkt_len, pkt_offset, tp_len; + int is_cfg_packet; + u8 *buff_ptr; + + do { + buff_ptr = buffer + offset; + memcpy(&header, buff_ptr, 4); + header = cpu_to_le32(header); + + is_cfg_packet = (header >> 31) & 0x1; + pkt_offset = (header >> 22) & 0x1ff; + tp_len = (header >> 11) & 0x7ff; + pkt_len = header & 0x7ff; + + if (pkt_len == 0 || tp_len == 0) + break; + + if (pkt_offset & IS_MANAGMEMENT) { + pkt_offset &= ~(IS_MANAGMEMENT | + IS_MANAGMEMENT_CALLBACK | + IS_MGMT_STATUS_SUCCES); + buff_ptr += HOST_HDR_OFFSET; + wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len); + } else { + if (!is_cfg_packet) { + if (pkt_len > 0) { + wilc_frmw_to_linux(wilc, buff_ptr, + pkt_len, + pkt_offset); + } + } else { + struct wilc_cfg_rsp rsp; + + buff_ptr += pkt_offset; + + wilc_wlan_cfg_indicate_rx(wilc, buff_ptr, + pkt_len, + &rsp); + if (rsp.type == WILC_CFG_RSP) { + if (wilc->cfg_seq_no == rsp.seq_no) + complete(&wilc->cfg_event); + } else if (rsp.type == WILC_CFG_RSP_STATUS) { + wilc_mac_indicate(wilc, + WILC_MAC_INDICATE_STATUS); + + } else if (rsp.type == WILC_CFG_RSP_SCAN) { + wilc_mac_indicate(wilc, + WILC_MAC_INDICATE_SCAN); + } + } + } + offset += tp_len; + if (offset >= size) + break; + } while (1); +} + static void wilc_wlan_handle_rxq(struct wilc *wilc) { - int offset = 0, size; + int size; u8 *buffer; struct rxq_entry_t *rqe; @@ -779,61 +853,8 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc) buffer = rqe->buffer; size = rqe->buffer_size; - offset = 0; - - do { - u32 header; - u32 pkt_len, pkt_offset, tp_len; - int is_cfg_packet; + wilc_wlan_handle_rx_buff(wilc, buffer, size); - memcpy(&header, &buffer[offset], 4); - header = cpu_to_le32(header); - - is_cfg_packet = (header >> 31) & 0x1; - pkt_offset = (header >> 22) & 0x1ff; - tp_len = (header >> 11) & 0x7ff; - pkt_len = header & 0x7ff; - - if (pkt_len == 0 || tp_len == 0) - break; - - #define IS_MANAGMEMENT 0x100 - #define IS_MANAGMEMENT_CALLBACK 0x080 - #define IS_MGMT_STATUS_SUCCES 0x040 - - if (pkt_offset & IS_MANAGMEMENT) { - pkt_offset &= ~(IS_MANAGMEMENT | - IS_MANAGMEMENT_CALLBACK | - IS_MGMT_STATUS_SUCCES); - - WILC_WFI_mgmt_rx(wilc, &buffer[offset + HOST_HDR_OFFSET], pkt_len); - } else { - if (!is_cfg_packet) { - if (pkt_len > 0) { - wilc_frmw_to_linux(wilc, - &buffer[offset], - pkt_len, - pkt_offset); - } - } else { - struct wilc_cfg_rsp rsp; - - wilc_wlan_cfg_indicate_rx(wilc, &buffer[pkt_offset + offset], pkt_len, &rsp); - if (rsp.type == WILC_CFG_RSP) { - if (wilc->cfg_seq_no == rsp.seq_no) - complete(&wilc->cfg_event); - } else if (rsp.type == WILC_CFG_RSP_STATUS) { - wilc_mac_indicate(wilc, WILC_MAC_INDICATE_STATUS); - - } else if (rsp.type == WILC_CFG_RSP_SCAN) { - wilc_mac_indicate(wilc, WILC_MAC_INDICATE_SCAN); - } - } - } - offset += tp_len; - if (offset >= size) - break; - } while (1); kfree(rqe); } while (1); @@ -1216,27 +1237,28 @@ int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer, offset += ret_size; wilc->cfg_frame_offset = offset; - if (commit) { - netdev_dbg(vif->ndev, - "[WILC]PACKET Commit with sequence number %d\n", - wilc->cfg_seq_no); - netdev_dbg(vif->ndev, "Processing cfg_set()\n"); - wilc->cfg_frame_in_use = 1; + if (!commit) + return ret_size; - if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler)) - ret_size = 0; + netdev_dbg(vif->ndev, + "[WILC]PACKET Commit with sequence number %d\n", + wilc->cfg_seq_no); + netdev_dbg(vif->ndev, "Processing cfg_set()\n"); + wilc->cfg_frame_in_use = 1; - if (!wait_for_completion_timeout(&wilc->cfg_event, - msecs_to_jiffies(CFG_PKTS_TIMEOUT))) { - netdev_dbg(vif->ndev, "Set Timed Out\n"); - ret_size = 0; - } + if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler)) + ret_size = 0; - wilc->cfg_frame_in_use = 0; - wilc->cfg_frame_offset = 0; - wilc->cfg_seq_no += 1; + if (!wait_for_completion_timeout(&wilc->cfg_event, + msecs_to_jiffies(CFG_PKTS_TIMEOUT))) { + netdev_dbg(vif->ndev, "Set Timed Out\n"); + ret_size = 0; } + wilc->cfg_frame_in_use = 0; + wilc->cfg_frame_offset = 0; + wilc->cfg_seq_no += 1; + return ret_size; } @@ -1258,21 +1280,22 @@ int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, offset += ret_size; wilc->cfg_frame_offset = offset; - if (commit) { - wilc->cfg_frame_in_use = 1; + if (!commit) + return ret_size; - if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler)) - ret_size = 0; + wilc->cfg_frame_in_use = 1; - if (!wait_for_completion_timeout(&wilc->cfg_event, - msecs_to_jiffies(CFG_PKTS_TIMEOUT))) { - netdev_dbg(vif->ndev, "Get Timed Out\n"); - ret_size = 0; - } - wilc->cfg_frame_in_use = 0; - wilc->cfg_frame_offset = 0; - wilc->cfg_seq_no += 1; + if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler)) + ret_size = 0; + + if (!wait_for_completion_timeout(&wilc->cfg_event, + msecs_to_jiffies(CFG_PKTS_TIMEOUT))) { + netdev_dbg(vif->ndev, "Get Timed Out\n"); + ret_size = 0; } + wilc->cfg_frame_in_use = 0; + wilc->cfg_frame_offset = 0; + wilc->cfg_seq_no += 1; return ret_size; } diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wilc_wlan.h index da7173105497..fa157a67b045 100644 --- a/drivers/staging/wilc1000/wilc_wlan.h +++ b/drivers/staging/wilc1000/wilc_wlan.h @@ -195,6 +195,11 @@ #define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM) /*time for expiring the completion of cfg packets*/ #define CFG_PKTS_TIMEOUT 2000 + +#define IS_MANAGMEMENT 0x100 +#define IS_MANAGMEMENT_CALLBACK 0x080 +#define IS_MGMT_STATUS_SUCCES 0x040 + /******************************************** * * Debug Type diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c index aeb5417f3587..2b44f4cc56b7 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.c +++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c @@ -221,7 +221,8 @@ static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32) return 8; } -static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str, u32 size) +static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str, + u32 size) { u8 *buf; @@ -483,20 +484,21 @@ int wilc_wlan_cfg_get_wid_value(u16 wid, u8 *buffer, u32 buffer_size) } while (1); } else if (type == CFG_STR_CMD) { do { - if (g_cfg_str[i].id == WID_NIL) + u32 id = g_cfg_str[i].id; + + if (id == WID_NIL) break; - if (g_cfg_str[i].id == wid) { + if (id == wid) { u32 size = g_cfg_str[i].str[0] | (g_cfg_str[i].str[1] << 8); if (buffer_size >= size) { - if (g_cfg_str[i].id == WID_SITE_SURVEY_RESULTS) { + if (id == WID_SITE_SURVEY_RESULTS) { static int toggle; i += toggle; toggle ^= 1; - } memcpy(buffer, &g_cfg_str[i].str[2], size); @@ -523,9 +525,12 @@ int wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, frame += 4; size -= 4; - /** - * The valid types of response messages are 'R' (Response), 'I' (Information), and 'N' (Network Information) - **/ + /* + * The valid types of response messages are + * 'R' (Response), + * 'I' (Information), and + * 'N' (Network Information) + */ switch (msg_type) { case 'R': diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index 78934e435fcf..d7de9e9c47a2 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -563,7 +563,7 @@ int prism2mgmt_start(struct wlandevice *wlandev, void *msgp) /*** STATION ***/ /* Set the REQUIRED config items */ /* SSID */ - pstr = (struct p80211pstrd *)&(msg->ssid.data); + pstr = (struct p80211pstrd *)&msg->ssid.data; prism2mgmt_pstr2bytestr(p2bytestr, pstr); result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFOWNSSID, bytebuf, HFA384x_RID_CNFOWNSSID_LEN); diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 10107de0119a..eca0b50f0df6 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -544,41 +544,42 @@ static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info, yres = XGIbios_mode[xgifb_info->mode_idx].yres; xgifb_info->rate_idx = 0; - while ((XGIfb_vrate[i].idx != 0) && (XGIfb_vrate[i].xres <= xres)) { - if ((XGIfb_vrate[i].xres == xres) && - (XGIfb_vrate[i].yres == yres)) { - if (XGIfb_vrate[i].refresh == rate) { + + while (XGIfb_vrate[i].idx != 0 && XGIfb_vrate[i].xres <= xres) { + /* Skip values with xres or yres less than specified */ + if ((XGIfb_vrate[i].yres != yres) || + (XGIfb_vrate[i].xres != xres)) { + i++; + continue; + } + if (XGIfb_vrate[i].refresh == rate) { + xgifb_info->rate_idx = XGIfb_vrate[i].idx; + break; + } else if (XGIfb_vrate[i].refresh > rate) { + if (XGIfb_vrate[i].refresh - rate <= 3) { + pr_debug("Adjusting rate from %d up to %d\n", + rate, XGIfb_vrate[i].refresh); xgifb_info->rate_idx = XGIfb_vrate[i].idx; - break; - } else if (XGIfb_vrate[i].refresh > rate) { - if ((XGIfb_vrate[i].refresh - rate) <= 3) { - pr_debug("Adjusting rate from %d up to %d\n", - rate, XGIfb_vrate[i].refresh); - xgifb_info->rate_idx = - XGIfb_vrate[i].idx; - xgifb_info->refresh_rate = - XGIfb_vrate[i].refresh; - } else if (((rate - XGIfb_vrate[i - 1].refresh) - <= 2) && (XGIfb_vrate[i].idx - != 1)) { - pr_debug("Adjusting rate from %d down to %d\n", - rate, - XGIfb_vrate[i - 1].refresh); - xgifb_info->rate_idx = - XGIfb_vrate[i - 1].idx; - xgifb_info->refresh_rate = - XGIfb_vrate[i - 1].refresh; - } - break; - } else if ((rate - XGIfb_vrate[i].refresh) <= 2) { + xgifb_info->refresh_rate = + XGIfb_vrate[i].refresh; + } else if ((XGIfb_vrate[i].idx != 1) && + (rate - XGIfb_vrate[i - 1].refresh <= 2)) { pr_debug("Adjusting rate from %d down to %d\n", - rate, XGIfb_vrate[i].refresh); - xgifb_info->rate_idx = XGIfb_vrate[i].idx; - break; + rate, XGIfb_vrate[i - 1].refresh); + xgifb_info->rate_idx = XGIfb_vrate[i - 1].idx; + xgifb_info->refresh_rate = + XGIfb_vrate[i - 1].refresh; } + break; + } else if (rate - XGIfb_vrate[i].refresh <= 2) { + pr_debug("Adjusting rate from %d down to %d\n", + rate, XGIfb_vrate[i].refresh); + xgifb_info->rate_idx = XGIfb_vrate[i].idx; + break; } i++; } + if (xgifb_info->rate_idx > 0) return xgifb_info->rate_idx; pr_info("Unsupported rate %d for %dx%d\n", diff --git a/drivers/staging/fsl-mc/include/mc.h b/include/linux/fsl/mc.h index 765ba41f5987..f27cb14088a4 100644 --- a/drivers/staging/fsl-mc/include/mc.h +++ b/include/linux/fsl/mc.h @@ -209,7 +209,7 @@ struct mc_cmd_header { __le16 cmd_id; }; -struct mc_command { +struct fsl_mc_command { u64 header; u64 params[MC_CMD_NUM_OF_PARAMS]; }; @@ -256,7 +256,7 @@ static inline u64 mc_encode_cmd_header(u16 cmd_id, return header; } -static inline u16 mc_cmd_hdr_read_token(struct mc_command *cmd) +static inline u16 mc_cmd_hdr_read_token(struct fsl_mc_command *cmd) { struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; u16 token = le16_to_cpu(hdr->token); @@ -273,7 +273,7 @@ struct mc_rsp_api_ver { __le16 minor_ver; }; -static inline u32 mc_cmd_read_object_id(struct mc_command *cmd) +static inline u32 mc_cmd_read_object_id(struct fsl_mc_command *cmd) { struct mc_rsp_create *rsp_params; @@ -281,7 +281,7 @@ static inline u32 mc_cmd_read_object_id(struct mc_command *cmd) return le32_to_cpu(rsp_params->object_id); } -static inline void mc_cmd_read_api_version(struct mc_command *cmd, +static inline void mc_cmd_read_api_version(struct fsl_mc_command *cmd, u16 *major_ver, u16 *minor_ver) { @@ -342,7 +342,7 @@ struct fsl_mc_io { }; }; -int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd); +int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd); #ifdef CONFIG_FSL_MC_BUS #define dev_is_fsl_mc(_dev) ((_dev)->bus == &fsl_mc_bus_type) @@ -451,4 +451,112 @@ static inline bool is_fsl_mc_bus_dprtc(const struct fsl_mc_device *mc_dev) return mc_dev->dev.type == &fsl_mc_bus_dprtc_type; } +/* + * Data Path Buffer Pool (DPBP) API + * Contains initialization APIs and runtime control APIs for DPBP + */ + +int dpbp_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dpbp_id, + u16 *token); + +int dpbp_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpbp_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpbp_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpbp_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +/** + * struct dpbp_attr - Structure representing DPBP attributes + * @id: DPBP object ID + * @bpid: Hardware buffer pool ID; should be used as an argument in + * acquire/release operations on buffers + */ +struct dpbp_attr { + int id; + u16 bpid; +}; + +int dpbp_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpbp_attr *attr); + +/* Data Path Concentrator (DPCON) API + * Contains initialization APIs and runtime control APIs for DPCON + */ + +/** + * Use it to disable notifications; see dpcon_set_notification() + */ +#define DPCON_INVALID_DPIO_ID (int)(-1) + +int dpcon_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dpcon_id, + u16 *token); + +int dpcon_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpcon_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpcon_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dpcon_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +/** + * struct dpcon_attr - Structure representing DPCON attributes + * @id: DPCON object ID + * @qbman_ch_id: Channel ID to be used by dequeue operation + * @num_priorities: Number of priorities for the DPCON channel (1-8) + */ +struct dpcon_attr { + int id; + u16 qbman_ch_id; + u8 num_priorities; +}; + +int dpcon_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpcon_attr *attr); + +/** + * struct dpcon_notification_cfg - Structure representing notification params + * @dpio_id: DPIO object ID; must be configured with a notification channel; + * to disable notifications set it to 'DPCON_INVALID_DPIO_ID'; + * @priority: Priority selection within the DPIO channel; valid values + * are 0-7, depending on the number of priorities in that channel + * @user_ctx: User context value provided with each CDAN message + */ +struct dpcon_notification_cfg { + int dpio_id; + u8 priority; + u64 user_ctx; +}; + +int dpcon_set_notification(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpcon_notification_cfg *cfg); + #endif /* _FSL_MC_H_ */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 293fa0677fba..3cbf3cfff4f0 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -480,6 +480,15 @@ extern int func_ptr_is_kernel_text(void *ptr); unsigned long int_sqrt(unsigned long); +#if BITS_PER_LONG < 64 +u32 int_sqrt64(u64 x); +#else +static inline u32 int_sqrt64(u64 x) +{ + return (u32)int_sqrt(x); +} +#endif + extern void bust_spinlocks(int yes); extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */ extern int panic_timeout; diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index 080798f17ece..82bf7747b312 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -266,6 +266,8 @@ enum axp20x_variants { #define AXP288_RT_BATT_V_H 0xa0 #define AXP288_RT_BATT_V_L 0xa1 +#define AXP813_ADC_RATE 0x85 + /* Fuel Gauge */ #define AXP288_FG_RDC1_REG 0xba #define AXP288_FG_RDC0_REG 0xbb diff --git a/include/linux/wait.h b/include/linux/wait.h index 55a611486bac..d9f131ecf708 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -599,6 +599,120 @@ do { \ __ret; \ }) +/** + * wait_event_idle - wait for a condition without contributing to system load + * @wq_head: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_IDLE) until the + * @condition evaluates to true. + * The @condition is checked each time the waitqueue @wq_head is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + */ +#define wait_event_idle(wq_head, condition) \ +do { \ + might_sleep(); \ + if (!(condition)) \ + ___wait_event(wq_head, condition, TASK_IDLE, 0, 0, schedule()); \ +} while (0) + +/** + * wait_event_idle_exclusive - wait for a condition with contributing to system load + * @wq_head: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_IDLE) until the + * @condition evaluates to true. + * The @condition is checked each time the waitqueue @wq_head is woken up. + * + * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag + * set thus if other processes wait on the same list, when this + * process is woken further processes are not considered. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + */ +#define wait_event_idle_exclusive(wq_head, condition) \ +do { \ + might_sleep(); \ + if (!(condition)) \ + ___wait_event(wq_head, condition, TASK_IDLE, 1, 0, schedule()); \ +} while (0) + +#define __wait_event_idle_timeout(wq_head, condition, timeout) \ + ___wait_event(wq_head, ___wait_cond_timeout(condition), \ + TASK_IDLE, 0, timeout, \ + __ret = schedule_timeout(__ret)) + +/** + * wait_event_idle_timeout - sleep without load until a condition becomes true or a timeout elapses + * @wq_head: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * @timeout: timeout, in jiffies + * + * The process is put to sleep (TASK_IDLE) until the + * @condition evaluates to true. The @condition is checked each time + * the waitqueue @wq_head is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + * Returns: + * 0 if the @condition evaluated to %false after the @timeout elapsed, + * 1 if the @condition evaluated to %true after the @timeout elapsed, + * or the remaining jiffies (at least 1) if the @condition evaluated + * to %true before the @timeout elapsed. + */ +#define wait_event_idle_timeout(wq_head, condition, timeout) \ +({ \ + long __ret = timeout; \ + might_sleep(); \ + if (!___wait_cond_timeout(condition)) \ + __ret = __wait_event_idle_timeout(wq_head, condition, timeout); \ + __ret; \ +}) + +#define __wait_event_idle_exclusive_timeout(wq_head, condition, timeout) \ + ___wait_event(wq_head, ___wait_cond_timeout(condition), \ + TASK_IDLE, 1, timeout, \ + __ret = schedule_timeout(__ret)) + +/** + * wait_event_idle_exclusive_timeout - sleep without load until a condition becomes true or a timeout elapses + * @wq_head: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * @timeout: timeout, in jiffies + * + * The process is put to sleep (TASK_IDLE) until the + * @condition evaluates to true. The @condition is checked each time + * the waitqueue @wq_head is woken up. + * + * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag + * set thus if other processes wait on the same list, when this + * process is woken further processes are not considered. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + * Returns: + * 0 if the @condition evaluated to %false after the @timeout elapsed, + * 1 if the @condition evaluated to %true after the @timeout elapsed, + * or the remaining jiffies (at least 1) if the @condition evaluated + * to %true before the @timeout elapsed. + */ +#define wait_event_idle_exclusive_timeout(wq_head, condition, timeout) \ +({ \ + long __ret = timeout; \ + might_sleep(); \ + if (!___wait_cond_timeout(condition)) \ + __ret = __wait_event_idle_exclusive_timeout(wq_head, condition, timeout);\ + __ret; \ +}) + extern int do_wait_intr(wait_queue_head_t *, wait_queue_entry_t *); extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_entry_t *); diff --git a/include/uapi/linux/irda.h b/include/uapi/linux/irda.h deleted file mode 100644 index 2105c266aa6e..000000000000 --- a/include/uapi/linux/irda.h +++ /dev/null @@ -1,252 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/********************************************************************* - * - * Filename: irda.h - * Version: - * Description: - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Mon Mar 8 14:06:12 1999 - * Modified at: Sat Dec 25 16:06:42 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef KERNEL_IRDA_H -#define KERNEL_IRDA_H - -#include <linux/types.h> -#include <linux/socket.h> - -/* Note that this file is shared with user space. */ - -/* Hint bit positions for first hint byte */ -#define HINT_PNP 0x01 -#define HINT_PDA 0x02 -#define HINT_COMPUTER 0x04 -#define HINT_PRINTER 0x08 -#define HINT_MODEM 0x10 -#define HINT_FAX 0x20 -#define HINT_LAN 0x40 -#define HINT_EXTENSION 0x80 - -/* Hint bit positions for second hint byte (first extension byte) */ -#define HINT_TELEPHONY 0x01 -#define HINT_FILE_SERVER 0x02 -#define HINT_COMM 0x04 -#define HINT_MESSAGE 0x08 -#define HINT_HTTP 0x10 -#define HINT_OBEX 0x20 - -/* IrLMP character code values */ -#define CS_ASCII 0x00 -#define CS_ISO_8859_1 0x01 -#define CS_ISO_8859_2 0x02 -#define CS_ISO_8859_3 0x03 -#define CS_ISO_8859_4 0x04 -#define CS_ISO_8859_5 0x05 -#define CS_ISO_8859_6 0x06 -#define CS_ISO_8859_7 0x07 -#define CS_ISO_8859_8 0x08 -#define CS_ISO_8859_9 0x09 -#define CS_UNICODE 0xff - -/* These are the currently known dongles */ -typedef enum { - IRDA_TEKRAM_DONGLE = 0, - IRDA_ESI_DONGLE = 1, - IRDA_ACTISYS_DONGLE = 2, - IRDA_ACTISYS_PLUS_DONGLE = 3, - IRDA_GIRBIL_DONGLE = 4, - IRDA_LITELINK_DONGLE = 5, - IRDA_AIRPORT_DONGLE = 6, - IRDA_OLD_BELKIN_DONGLE = 7, - IRDA_EP7211_IR = 8, - IRDA_MCP2120_DONGLE = 9, - IRDA_ACT200L_DONGLE = 10, - IRDA_MA600_DONGLE = 11, - IRDA_TOIM3232_DONGLE = 12, - IRDA_EP7211_DONGLE = 13, -} IRDA_DONGLE; - -/* Protocol types to be used for SOCK_DGRAM */ -enum { - IRDAPROTO_UNITDATA = 0, - IRDAPROTO_ULTRA = 1, - IRDAPROTO_MAX -}; - -#define SOL_IRLMP 266 /* Same as SOL_IRDA for now */ -#define SOL_IRTTP 266 /* Same as SOL_IRDA for now */ - -#define IRLMP_ENUMDEVICES 1 /* Return discovery log */ -#define IRLMP_IAS_SET 2 /* Set an attribute in local IAS */ -#define IRLMP_IAS_QUERY 3 /* Query remote IAS for attribute */ -#define IRLMP_HINTS_SET 4 /* Set hint bits advertised */ -#define IRLMP_QOS_SET 5 -#define IRLMP_QOS_GET 6 -#define IRLMP_MAX_SDU_SIZE 7 -#define IRLMP_IAS_GET 8 /* Get an attribute from local IAS */ -#define IRLMP_IAS_DEL 9 /* Remove attribute from local IAS */ -#define IRLMP_HINT_MASK_SET 10 /* Set discovery filter */ -#define IRLMP_WAITDEVICE 11 /* Wait for a new discovery */ - -#define IRTTP_MAX_SDU_SIZE IRLMP_MAX_SDU_SIZE /* Compatibility */ - -#define IAS_MAX_STRING 256 /* See IrLMP 1.1, 4.3.3.2 */ -#define IAS_MAX_OCTET_STRING 1024 /* See IrLMP 1.1, 4.3.3.2 */ -#define IAS_MAX_CLASSNAME 60 /* See IrLMP 1.1, 4.3.1 */ -#define IAS_MAX_ATTRIBNAME 60 /* See IrLMP 1.1, 4.3.3.1 */ -#define IAS_MAX_ATTRIBNUMBER 256 /* See IrLMP 1.1, 4.3.3.1 */ -/* For user space backward compatibility - may be fixed in kernel 2.5.X - * Note : need 60+1 ('\0'), make it 64 for alignement - Jean II */ -#define IAS_EXPORT_CLASSNAME 64 -#define IAS_EXPORT_ATTRIBNAME 256 - -/* Attribute type needed for struct irda_ias_set */ -#define IAS_MISSING 0 -#define IAS_INTEGER 1 -#define IAS_OCT_SEQ 2 -#define IAS_STRING 3 - -#define LSAP_ANY 0xff - -struct sockaddr_irda { - __kernel_sa_family_t sir_family; /* AF_IRDA */ - __u8 sir_lsap_sel; /* LSAP selector */ - __u32 sir_addr; /* Device address */ - char sir_name[25]; /* Usually <service>:IrDA:TinyTP */ -}; - -struct irda_device_info { - __u32 saddr; /* Address of local interface */ - __u32 daddr; /* Address of remote device */ - char info[22]; /* Description */ - __u8 charset; /* Charset used for description */ - __u8 hints[2]; /* Hint bits */ -}; - -struct irda_device_list { - __u32 len; - struct irda_device_info dev[1]; -}; - -struct irda_ias_set { - char irda_class_name[IAS_EXPORT_CLASSNAME]; - char irda_attrib_name[IAS_EXPORT_ATTRIBNAME]; - unsigned int irda_attrib_type; - union { - unsigned int irda_attrib_int; - struct { - unsigned short len; - __u8 octet_seq[IAS_MAX_OCTET_STRING]; - } irda_attrib_octet_seq; - struct { - __u8 len; - __u8 charset; - __u8 string[IAS_MAX_STRING]; - } irda_attrib_string; - } attribute; - __u32 daddr; /* Address of device (for some queries only) */ -}; - -/* Some private IOCTL's (max 16) */ -#define SIOCSDONGLE (SIOCDEVPRIVATE + 0) -#define SIOCGDONGLE (SIOCDEVPRIVATE + 1) -#define SIOCSBANDWIDTH (SIOCDEVPRIVATE + 2) -#define SIOCSMEDIABUSY (SIOCDEVPRIVATE + 3) -#define SIOCGMEDIABUSY (SIOCDEVPRIVATE + 4) -#define SIOCGRECEIVING (SIOCDEVPRIVATE + 5) -#define SIOCSMODE (SIOCDEVPRIVATE + 6) -#define SIOCGMODE (SIOCDEVPRIVATE + 7) -#define SIOCSDTRRTS (SIOCDEVPRIVATE + 8) -#define SIOCGQOS (SIOCDEVPRIVATE + 9) - -/* No reason to include <linux/if.h> just because of this one ;-) */ -#define IRNAMSIZ 16 - -/* IrDA quality of service information (must not exceed 16 bytes) */ -struct if_irda_qos { - unsigned long baudrate; - unsigned short data_size; - unsigned short window_size; - unsigned short min_turn_time; - unsigned short max_turn_time; - unsigned char add_bofs; - unsigned char link_disc; -}; - -/* For setting RTS and DTR lines of a dongle */ -struct if_irda_line { - __u8 dtr; - __u8 rts; -}; - -/* IrDA interface configuration (data part must not exceed 16 bytes) */ -struct if_irda_req { - union { - char ifrn_name[IRNAMSIZ]; /* if name, e.g. "irda0" */ - } ifr_ifrn; - - /* Data part */ - union { - struct if_irda_line ifru_line; - struct if_irda_qos ifru_qos; - unsigned short ifru_flags; - unsigned int ifru_receiving; - unsigned int ifru_mode; - unsigned int ifru_dongle; - } ifr_ifru; -}; - -#define ifr_baudrate ifr_ifru.ifru_qos.baudrate -#define ifr_receiving ifr_ifru.ifru_receiving -#define ifr_dongle ifr_ifru.ifru_dongle -#define ifr_mode ifr_ifru.ifru_mode -#define ifr_dtr ifr_ifru.ifru_line.dtr -#define ifr_rts ifr_ifru.ifru_line.rts - - -/* IrDA netlink definitions */ -#define IRDA_NL_NAME "irda" -#define IRDA_NL_VERSION 1 - -enum irda_nl_commands { - IRDA_NL_CMD_UNSPEC, - IRDA_NL_CMD_SET_MODE, - IRDA_NL_CMD_GET_MODE, - - __IRDA_NL_CMD_AFTER_LAST -}; -#define IRDA_NL_CMD_MAX (__IRDA_NL_CMD_AFTER_LAST - 1) - -enum nl80211_attrs { - IRDA_NL_ATTR_UNSPEC, - IRDA_NL_ATTR_IFNAME, - IRDA_NL_ATTR_MODE, - - __IRDA_NL_ATTR_AFTER_LAST -}; -#define IRDA_NL_ATTR_MAX (__IRDA_NL_ATTR_AFTER_LAST - 1) - -/* IrDA modes */ -#define IRDA_MODE_PRIMARY 0x1 -#define IRDA_MODE_SECONDARY 0x2 -#define IRDA_MODE_MONITOR 0x4 - -#endif /* KERNEL_IRDA_H */ - - - - diff --git a/include/uapi/linux/ixjuser.h b/include/uapi/linux/ixjuser.h deleted file mode 100644 index ba245007cfe7..000000000000 --- a/include/uapi/linux/ixjuser.h +++ /dev/null @@ -1,721 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -#ifndef __LINUX_IXJUSER_H -#define __LINUX_IXJUSER_H - -/****************************************************************************** - * - * ixjuser.h - * - * Device Driver for Quicknet Technologies, Inc.'s Telephony cards - * including the Internet PhoneJACK, Internet PhoneJACK Lite, - * Internet PhoneJACK PCI, Internet LineJACK, Internet PhoneCARD and - * SmartCABLE - * - * (c) Copyright 1999-2001 Quicknet Technologies, 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. - * - * Author: Ed Okerson, <eokerson@quicknet.net> - * - * Contributors: Greg Herlein, <gherlein@quicknet.net> - * David W. Erhart, <derhart@quicknet.net> - * John Sellers, <jsellers@quicknet.net> - * Mike Preston, <mpreston@quicknet.net> - * - * More information about the hardware related to this driver can be found - * at our website: http://www.quicknet.net - * - * Fixes: - * - * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT - * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET - * TECHNOLOGIES, INC.HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION - * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - *****************************************************************************/ - -#include <linux/telephony.h> - - -/****************************************************************************** -* -* IOCTL's used for the Quicknet Telephony Cards -* -* If you use the IXJCTL_TESTRAM command, the card must be power cycled to -* reset the SRAM values before further use. -* -******************************************************************************/ - -#define IXJCTL_DSP_RESET _IO ('q', 0xC0) - -#define IXJCTL_RING PHONE_RING -#define IXJCTL_HOOKSTATE PHONE_HOOKSTATE -#define IXJCTL_MAXRINGS PHONE_MAXRINGS -#define IXJCTL_RING_CADENCE PHONE_RING_CADENCE -#define IXJCTL_RING_START PHONE_RING_START -#define IXJCTL_RING_STOP PHONE_RING_STOP - -#define IXJCTL_CARDTYPE _IOR ('q', 0xC1, int) -#define IXJCTL_SERIAL _IOR ('q', 0xC2, int) -#define IXJCTL_DSP_TYPE _IOR ('q', 0xC3, int) -#define IXJCTL_DSP_VERSION _IOR ('q', 0xC4, int) -#define IXJCTL_VERSION _IOR ('q', 0xDA, char *) -#define IXJCTL_DSP_IDLE _IO ('q', 0xC5) -#define IXJCTL_TESTRAM _IO ('q', 0xC6) - -/****************************************************************************** -* -* This group of IOCTLs deal with the record settings of the DSP -* -* The IXJCTL_REC_DEPTH command sets the internal buffer depth of the DSP. -* Setting a lower depth reduces latency, but increases the demand of the -* application to service the driver without frame loss. The DSP has 480 -* bytes of physical buffer memory for the record channel so the true -* maximum limit is determined by how many frames will fit in the buffer. -* -* 1 uncompressed (480 byte) 16-bit linear frame. -* 2 uncompressed (240 byte) 8-bit A-law/mu-law frames. -* 15 TrueSpeech 8.5 frames. -* 20 TrueSpeech 6.3,5.3,4.8 or 4.1 frames. -* -* The default in the driver is currently set to 2 frames. -* -* The IXJCTL_REC_VOLUME and IXJCTL_PLAY_VOLUME commands both use a Q8 -* number as a parameter, 0x100 scales the signal by 1.0, 0x200 scales the -* signal by 2.0, 0x80 scales the signal by 0.5. No protection is given -* against over-scaling, if the multiplication factor times the input -* signal exceeds 16 bits, overflow distortion will occur. The default -* setting is 0x100 (1.0). -* -* The IXJCTL_REC_LEVEL returns the average signal level (not r.m.s.) on -* the most recently recorded frame as a 16 bit value. -******************************************************************************/ - -#define IXJCTL_REC_CODEC PHONE_REC_CODEC -#define IXJCTL_REC_START PHONE_REC_START -#define IXJCTL_REC_STOP PHONE_REC_STOP -#define IXJCTL_REC_DEPTH PHONE_REC_DEPTH -#define IXJCTL_FRAME PHONE_FRAME -#define IXJCTL_REC_VOLUME PHONE_REC_VOLUME -#define IXJCTL_REC_LEVEL PHONE_REC_LEVEL - -typedef enum { - f300_640 = 4, f300_500, f1100, f350, f400, f480, f440, f620, f20_50, - f133_200, f300, f300_420, f330, f300_425, f330_440, f340, f350_400, - f350_440, f350_450, f360, f380_420, f392, f400_425, f400_440, f400_450, - f420, f425, f425_450, f425_475, f435, f440_450, f440_480, f445, f450, - f452, f475, f480_620, f494, f500, f520, f523, f525, f540_660, f587, - f590, f600, f660, f700, f740, f750, f750_1450, f770, f800, f816, f850, - f857_1645, f900, f900_1300, f935_1215, f941_1477, f942, f950, f950_1400, - f975, f1000, f1020, f1050, f1100_1750, f1140, f1200, f1209, f1330, f1336, - lf1366, f1380, f1400, f1477, f1600, f1633_1638, f1800, f1860 -} IXJ_FILTER_FREQ; - -typedef struct { - unsigned int filter; - IXJ_FILTER_FREQ freq; - char enable; -} IXJ_FILTER; - -typedef struct { - char enable; - char en_filter; - unsigned int filter; - unsigned int on1; - unsigned int off1; - unsigned int on2; - unsigned int off2; - unsigned int on3; - unsigned int off3; -} IXJ_FILTER_CADENCE; - -#define IXJCTL_SET_FILTER _IOW ('q', 0xC7, IXJ_FILTER *) -#define IXJCTL_SET_FILTER_RAW _IOW ('q', 0xDD, IXJ_FILTER_RAW *) -#define IXJCTL_GET_FILTER_HIST _IOW ('q', 0xC8, int) -#define IXJCTL_FILTER_CADENCE _IOW ('q', 0xD6, IXJ_FILTER_CADENCE *) -#define IXJCTL_PLAY_CID _IO ('q', 0xD7) -/****************************************************************************** -* -* This IOCTL allows you to reassign values in the tone index table. The -* tone table has 32 entries (0 - 31), but the driver only allows entries -* 13 - 27 to be modified, entry 0 is reserved for silence and 1 - 12 are -* the standard DTMF digits and 28 - 31 are the DTMF tones for A, B, C & D. -* The positions used internally for Call Progress Tones are as follows: -* Dial Tone - 25 -* Ring Back - 26 -* Busy Signal - 27 -* -* The freq values are calculated as: -* freq = cos(2 * PI * frequency / 8000) -* -* The most commonly needed values are already calculated and listed in the -* enum IXJ_TONE_FREQ. Each tone index can have two frequencies with -* different gains, if you are only using a single frequency set the unused -* one to 0. -* -* The gain values range from 0 to 15 indicating +6dB to -24dB in 2dB -* increments. -* -******************************************************************************/ - -typedef enum { - hz20 = 0x7ffa, - hz50 = 0x7fe5, - hz133 = 0x7f4c, - hz200 = 0x7e6b, - hz261 = 0x7d50, /* .63 C1 */ - hz277 = 0x7cfa, /* .18 CS1 */ - hz293 = 0x7c9f, /* .66 D1 */ - hz300 = 0x7c75, - hz311 = 0x7c32, /* .13 DS1 */ - hz329 = 0x7bbf, /* .63 E1 */ - hz330 = 0x7bb8, - hz340 = 0x7b75, - hz349 = 0x7b37, /* .23 F1 */ - hz350 = 0x7b30, - hz360 = 0x7ae9, - hz369 = 0x7aa8, /* .99 FS1 */ - hz380 = 0x7a56, - hz392 = 0x79fa, /* .00 G1 */ - hz400 = 0x79bb, - hz415 = 0x7941, /* .30 GS1 */ - hz420 = 0x7918, - hz425 = 0x78ee, - hz435 = 0x7899, - hz440 = 0x786d, /* .00 A1 */ - hz445 = 0x7842, - hz450 = 0x7815, - hz452 = 0x7803, - hz466 = 0x7784, /* .16 AS1 */ - hz475 = 0x7731, - hz480 = 0x7701, - hz493 = 0x7685, /* .88 B1 */ - hz494 = 0x767b, - hz500 = 0x7640, - hz520 = 0x7578, - hz523 = 0x7559, /* .25 C2 */ - hz525 = 0x7544, - hz540 = 0x74a7, - hz554 = 0x7411, /* .37 CS2 */ - hz587 = 0x72a1, /* .33 D2 */ - hz590 = 0x727f, - hz600 = 0x720b, - hz620 = 0x711e, - hz622 = 0x7106, /* .25 DS2 */ - hz659 = 0x6f3b, /* .26 E2 */ - hz660 = 0x6f2e, - hz698 = 0x6d3d, /* .46 F2 */ - hz700 = 0x6d22, - hz739 = 0x6b09, /* .99 FS2 */ - hz740 = 0x6afa, - hz750 = 0x6a6c, - hz770 = 0x694b, - hz783 = 0x688b, /* .99 G2 */ - hz800 = 0x678d, - hz816 = 0x6698, - hz830 = 0x65bf, /* .61 GS2 */ - hz850 = 0x6484, - hz857 = 0x6414, - hz880 = 0x629f, /* .00 A2 */ - hz900 = 0x6154, - hz932 = 0x5f35, /* .33 AS2 */ - hz935 = 0x5f01, - hz941 = 0x5e9a, - hz942 = 0x5e88, - hz950 = 0x5dfd, - hz975 = 0x5c44, - hz1000 = 0x5a81, - hz1020 = 0x5912, - hz1050 = 0x56e2, - hz1100 = 0x5320, - hz1140 = 0x5007, - hz1200 = 0x4b3b, - hz1209 = 0x4a80, - hz1215 = 0x4a02, - hz1250 = 0x471c, - hz1300 = 0x42e0, - hz1330 = 0x4049, - hz1336 = 0x3fc4, - hz1366 = 0x3d22, - hz1380 = 0x3be4, - hz1400 = 0x3a1b, - hz1450 = 0x3596, - hz1477 = 0x331c, - hz1500 = 0x30fb, - hz1600 = 0x278d, - hz1633 = 0x2462, - hz1638 = 0x23e7, - hz1645 = 0x233a, - hz1750 = 0x18f8, - hz1800 = 0x1405, - hz1860 = 0xe0b, - hz2100 = 0xf5f6, - hz2130 = 0xf2f5, - hz2450 = 0xd3b3, - hz2750 = 0xb8e4 -} IXJ_FREQ; - -typedef enum { - C1 = hz261, - CS1 = hz277, - D1 = hz293, - DS1 = hz311, - E1 = hz329, - F1 = hz349, - FS1 = hz369, - G1 = hz392, - GS1 = hz415, - A1 = hz440, - AS1 = hz466, - B1 = hz493, - C2 = hz523, - CS2 = hz554, - D2 = hz587, - DS2 = hz622, - E2 = hz659, - F2 = hz698, - FS2 = hz739, - G2 = hz783, - GS2 = hz830, - A2 = hz880, - AS2 = hz932, -} IXJ_NOTE; - -typedef struct { - int tone_index; - int freq0; - int gain0; - int freq1; - int gain1; -} IXJ_TONE; - -#define IXJCTL_INIT_TONE _IOW ('q', 0xC9, IXJ_TONE *) - -/****************************************************************************** -* -* The IXJCTL_TONE_CADENCE ioctl defines tone sequences used for various -* Call Progress Tones (CPT). This is accomplished by setting up an array of -* IXJ_CADENCE_ELEMENT structures that sequentially define the states of -* the tone sequence. The tone_on_time and tone_off time are in -* 250 microsecond intervals. A pointer to this array is passed to the -* driver as the ce element of an IXJ_CADENCE structure. The elements_used -* must be set to the number of IXJ_CADENCE_ELEMENTS in the array. The -* termination variable defines what to do at the end of a cadence, the -* options are to play the cadence once and stop, to repeat the last -* element of the cadence indefinitely, or to repeat the entire cadence -* indefinitely. The ce variable is a pointer to the array of IXJ_TONE -* structures. If the freq0 variable is non-zero, the tone table contents -* for the tone_index are updated to the frequencies and gains defined. It -* should be noted that DTMF tones cannot be reassigned, so if DTMF tone -* table indexes are used in a cadence the frequency and gain variables will -* be ignored. -* -* If the array elements contain frequency parameters the driver will -* initialize the needed tone table elements and begin playing the tone, -* there is no preset limit on the number of elements in the cadence. If -* there is more than one frequency used in the cadence, sequential elements -* of different frequencies MUST use different tone table indexes. Only one -* cadence can be played at a time. It is possible to build complex -* cadences with multiple frequencies using 2 tone table indexes by -* alternating between them. -* -******************************************************************************/ - -typedef struct { - int index; - int tone_on_time; - int tone_off_time; - int freq0; - int gain0; - int freq1; - int gain1; -} IXJ_CADENCE_ELEMENT; - -typedef enum { - PLAY_ONCE, - REPEAT_LAST_ELEMENT, - REPEAT_ALL -} IXJ_CADENCE_TERM; - -typedef struct { - int elements_used; - IXJ_CADENCE_TERM termination; - IXJ_CADENCE_ELEMENT __user *ce; -} IXJ_CADENCE; - -#define IXJCTL_TONE_CADENCE _IOW ('q', 0xCA, IXJ_CADENCE *) -/****************************************************************************** -* -* This group of IOCTLs deal with the playback settings of the DSP -* -******************************************************************************/ - -#define IXJCTL_PLAY_CODEC PHONE_PLAY_CODEC -#define IXJCTL_PLAY_START PHONE_PLAY_START -#define IXJCTL_PLAY_STOP PHONE_PLAY_STOP -#define IXJCTL_PLAY_DEPTH PHONE_PLAY_DEPTH -#define IXJCTL_PLAY_VOLUME PHONE_PLAY_VOLUME -#define IXJCTL_PLAY_LEVEL PHONE_PLAY_LEVEL - -/****************************************************************************** -* -* This group of IOCTLs deal with the Acoustic Echo Cancellation settings -* of the DSP -* -* Issuing the IXJCTL_AEC_START command with a value of AEC_OFF has the -* same effect as IXJCTL_AEC_STOP. This is to simplify slider bar -* controls. IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC. -******************************************************************************/ -#define IXJCTL_AEC_START _IOW ('q', 0xCB, int) -#define IXJCTL_AEC_STOP _IO ('q', 0xCC) -#define IXJCTL_AEC_GET_LEVEL _IO ('q', 0xCD) - -#define AEC_OFF 0 -#define AEC_LOW 1 -#define AEC_MED 2 -#define AEC_HIGH 3 -#define AEC_AUTO 4 -#define AEC_AGC 5 -/****************************************************************************** -* -* Call Progress Tones, DTMF, etc. -* IXJCTL_DTMF_OOB determines if DTMF signaling is sent as Out-Of-Band -* only. If you pass a 1, DTMF is suppressed from the audio stream. -* Tone on and off times are in 250 microsecond intervals so -* ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360); -* will set the tone on time of board ixj1 to 360 * 250us = 90ms -* the default values of tone on and off times is 840 or 210ms -******************************************************************************/ - -#define IXJCTL_DTMF_READY PHONE_DTMF_READY -#define IXJCTL_GET_DTMF PHONE_GET_DTMF -#define IXJCTL_GET_DTMF_ASCII PHONE_GET_DTMF_ASCII -#define IXJCTL_DTMF_OOB PHONE_DTMF_OOB -#define IXJCTL_EXCEPTION PHONE_EXCEPTION -#define IXJCTL_PLAY_TONE PHONE_PLAY_TONE -#define IXJCTL_SET_TONE_ON_TIME PHONE_SET_TONE_ON_TIME -#define IXJCTL_SET_TONE_OFF_TIME PHONE_SET_TONE_OFF_TIME -#define IXJCTL_GET_TONE_ON_TIME PHONE_GET_TONE_ON_TIME -#define IXJCTL_GET_TONE_OFF_TIME PHONE_GET_TONE_OFF_TIME -#define IXJCTL_GET_TONE_STATE PHONE_GET_TONE_STATE -#define IXJCTL_BUSY PHONE_BUSY -#define IXJCTL_RINGBACK PHONE_RINGBACK -#define IXJCTL_DIALTONE PHONE_DIALTONE -#define IXJCTL_CPT_STOP PHONE_CPT_STOP - -/****************************************************************************** -* LineJACK specific IOCTLs -* -* The lsb 4 bits of the LED argument represent the state of each of the 4 -* LED's on the LineJACK -******************************************************************************/ - -#define IXJCTL_SET_LED _IOW ('q', 0xCE, int) -#define IXJCTL_MIXER _IOW ('q', 0xCF, int) - -/****************************************************************************** -* -* The master volume controls use attenuation with 32 levels from 0 to -62dB -* with steps of 2dB each, the defines should be OR'ed together then sent -* as the parameter to the mixer command to change the mixer settings. -* -******************************************************************************/ -#define MIXER_MASTER_L 0x0000 -#define MIXER_MASTER_R 0x0100 -#define ATT00DB 0x00 -#define ATT02DB 0x01 -#define ATT04DB 0x02 -#define ATT06DB 0x03 -#define ATT08DB 0x04 -#define ATT10DB 0x05 -#define ATT12DB 0x06 -#define ATT14DB 0x07 -#define ATT16DB 0x08 -#define ATT18DB 0x09 -#define ATT20DB 0x0A -#define ATT22DB 0x0B -#define ATT24DB 0x0C -#define ATT26DB 0x0D -#define ATT28DB 0x0E -#define ATT30DB 0x0F -#define ATT32DB 0x10 -#define ATT34DB 0x11 -#define ATT36DB 0x12 -#define ATT38DB 0x13 -#define ATT40DB 0x14 -#define ATT42DB 0x15 -#define ATT44DB 0x16 -#define ATT46DB 0x17 -#define ATT48DB 0x18 -#define ATT50DB 0x19 -#define ATT52DB 0x1A -#define ATT54DB 0x1B -#define ATT56DB 0x1C -#define ATT58DB 0x1D -#define ATT60DB 0x1E -#define ATT62DB 0x1F -#define MASTER_MUTE 0x80 - -/****************************************************************************** -* -* The input volume controls use gain with 32 levels from +12dB to -50dB -* with steps of 2dB each, the defines should be OR'ed together then sent -* as the parameter to the mixer command to change the mixer settings. -* -******************************************************************************/ -#define MIXER_PORT_CD_L 0x0600 -#define MIXER_PORT_CD_R 0x0700 -#define MIXER_PORT_LINE_IN_L 0x0800 -#define MIXER_PORT_LINE_IN_R 0x0900 -#define MIXER_PORT_POTS_REC 0x0C00 -#define MIXER_PORT_MIC 0x0E00 - -#define GAIN12DB 0x00 -#define GAIN10DB 0x01 -#define GAIN08DB 0x02 -#define GAIN06DB 0x03 -#define GAIN04DB 0x04 -#define GAIN02DB 0x05 -#define GAIN00DB 0x06 -#define GAIN_02DB 0x07 -#define GAIN_04DB 0x08 -#define GAIN_06DB 0x09 -#define GAIN_08DB 0x0A -#define GAIN_10DB 0x0B -#define GAIN_12DB 0x0C -#define GAIN_14DB 0x0D -#define GAIN_16DB 0x0E -#define GAIN_18DB 0x0F -#define GAIN_20DB 0x10 -#define GAIN_22DB 0x11 -#define GAIN_24DB 0x12 -#define GAIN_26DB 0x13 -#define GAIN_28DB 0x14 -#define GAIN_30DB 0x15 -#define GAIN_32DB 0x16 -#define GAIN_34DB 0x17 -#define GAIN_36DB 0x18 -#define GAIN_38DB 0x19 -#define GAIN_40DB 0x1A -#define GAIN_42DB 0x1B -#define GAIN_44DB 0x1C -#define GAIN_46DB 0x1D -#define GAIN_48DB 0x1E -#define GAIN_50DB 0x1F -#define INPUT_MUTE 0x80 - -/****************************************************************************** -* -* The POTS volume control use attenuation with 8 levels from 0dB to -28dB -* with steps of 4dB each, the defines should be OR'ed together then sent -* as the parameter to the mixer command to change the mixer settings. -* -******************************************************************************/ -#define MIXER_PORT_POTS_PLAY 0x0F00 - -#define POTS_ATT_00DB 0x00 -#define POTS_ATT_04DB 0x01 -#define POTS_ATT_08DB 0x02 -#define POTS_ATT_12DB 0x03 -#define POTS_ATT_16DB 0x04 -#define POTS_ATT_20DB 0x05 -#define POTS_ATT_24DB 0x06 -#define POTS_ATT_28DB 0x07 -#define POTS_MUTE 0x80 - -/****************************************************************************** -* -* The DAA controls the interface to the PSTN port. The driver loads the -* US coefficients by default, so if you live in a different country you -* need to load the set for your countries phone system. -* -******************************************************************************/ -#define IXJCTL_DAA_COEFF_SET _IOW ('q', 0xD0, int) - -#define DAA_US 1 /*PITA 8kHz */ -#define DAA_UK 2 /*ISAR34 8kHz */ -#define DAA_FRANCE 3 /* */ -#define DAA_GERMANY 4 -#define DAA_AUSTRALIA 5 -#define DAA_JAPAN 6 - -/****************************************************************************** -* -* Use IXJCTL_PORT to set or query the port the card is set to. If the -* argument is set to PORT_QUERY, the return value of the ioctl will -* indicate which port is currently in use, otherwise it will change the -* port. -* -******************************************************************************/ -#define IXJCTL_PORT _IOW ('q', 0xD1, int) - -#define PORT_QUERY 0 -#define PORT_POTS 1 -#define PORT_PSTN 2 -#define PORT_SPEAKER 3 -#define PORT_HANDSET 4 - -#define IXJCTL_PSTN_SET_STATE PHONE_PSTN_SET_STATE -#define IXJCTL_PSTN_GET_STATE PHONE_PSTN_GET_STATE - -#define PSTN_ON_HOOK 0 -#define PSTN_RINGING 1 -#define PSTN_OFF_HOOK 2 -#define PSTN_PULSE_DIAL 3 - -/****************************************************************************** -* -* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR), -* and the transmit gain (AGX). OR together the components and pass them -* as the parameter to IXJCTL_DAA_AGAIN. The default setting is both at 0dB. -* -******************************************************************************/ -#define IXJCTL_DAA_AGAIN _IOW ('q', 0xD2, int) - -#define AGRR00DB 0x00 /* Analog gain in receive direction 0dB */ -#define AGRR3_5DB 0x10 /* Analog gain in receive direction 3.5dB */ -#define AGRR06DB 0x30 /* Analog gain in receive direction 6dB */ - -#define AGX00DB 0x00 /* Analog gain in transmit direction 0dB */ -#define AGX_6DB 0x04 /* Analog gain in transmit direction -6dB */ -#define AGX3_5DB 0x08 /* Analog gain in transmit direction 3.5dB */ -#define AGX_2_5B 0x0C /* Analog gain in transmit direction -2.5dB */ - -#define IXJCTL_PSTN_LINETEST _IO ('q', 0xD3) - -#define IXJCTL_CID _IOR ('q', 0xD4, PHONE_CID *) -#define IXJCTL_VMWI _IOR ('q', 0xD8, int) -#define IXJCTL_CIDCW _IOW ('q', 0xD9, PHONE_CID *) -/****************************************************************************** -* -* The wink duration is tunable with this ioctl. The default wink duration -* is 320ms. You do not need to use this ioctl if you do not require a -* different wink duration. -* -******************************************************************************/ -#define IXJCTL_WINK_DURATION PHONE_WINK_DURATION - -/****************************************************************************** -* -* This ioctl will connect the POTS port to the PSTN port on the LineJACK -* In order for this to work properly the port selection should be set to -* the PSTN port with IXJCTL_PORT prior to calling this ioctl. This will -* enable conference calls between PSTN callers and network callers. -* Passing a 1 to this ioctl enables the POTS<->PSTN connection while -* passing a 0 turns it back off. -* -******************************************************************************/ -#define IXJCTL_POTS_PSTN _IOW ('q', 0xD5, int) - -/****************************************************************************** -* -* IOCTLs added by request. -* -* IXJCTL_HZ sets the value your Linux kernel uses for HZ as defined in -* /usr/include/asm/param.h, this determines the fundamental -* frequency of the clock ticks on your Linux system. The kernel -* must be rebuilt if you change this value, also all modules you -* use (except this one) must be recompiled. The default value -* is 100, and you only need to use this IOCTL if you use some -* other value. -* -* -* IXJCTL_RATE sets the number of times per second that the driver polls -* the DSP. This value cannot be larger than HZ. By -* increasing both of these values, you may be able to reduce -* latency because the max hang time that can exist between the -* driver and the DSP will be reduced. -* -******************************************************************************/ - -#define IXJCTL_HZ _IOW ('q', 0xE0, int) -#define IXJCTL_RATE _IOW ('q', 0xE1, int) -#define IXJCTL_FRAMES_READ _IOR ('q', 0xE2, unsigned long) -#define IXJCTL_FRAMES_WRITTEN _IOR ('q', 0xE3, unsigned long) -#define IXJCTL_READ_WAIT _IOR ('q', 0xE4, unsigned long) -#define IXJCTL_WRITE_WAIT _IOR ('q', 0xE5, unsigned long) -#define IXJCTL_DRYBUFFER_READ _IOR ('q', 0xE6, unsigned long) -#define IXJCTL_DRYBUFFER_CLEAR _IO ('q', 0xE7) -#define IXJCTL_DTMF_PRESCALE _IOW ('q', 0xE8, int) - -/****************************************************************************** -* -* This ioctl allows the user application to control what events the driver -* will send signals for, and what signals it will send for which event. -* By default, if signaling is enabled, all events will send SIGIO when -* they occur. To disable signals for an event set the signal to 0. -* -******************************************************************************/ -typedef enum { - SIG_DTMF_READY, - SIG_HOOKSTATE, - SIG_FLASH, - SIG_PSTN_RING, - SIG_CALLER_ID, - SIG_PSTN_WINK, - SIG_F0, SIG_F1, SIG_F2, SIG_F3, - SIG_FC0, SIG_FC1, SIG_FC2, SIG_FC3, - SIG_READ_READY = 33, - SIG_WRITE_READY = 34 -} IXJ_SIGEVENT; - -typedef struct { - unsigned int event; - int signal; -} IXJ_SIGDEF; - -#define IXJCTL_SIGCTL _IOW ('q', 0xE9, IXJ_SIGDEF *) - -/****************************************************************************** -* -* These ioctls allow the user application to change the gain in the -* Smart Cable of the Internet Phone Card. Sending -1 as a value will cause -* return value to be the current setting. Valid values to set are 0x00 - 0x1F -* -* 11111 = +12 dB -* 10111 = 0 dB -* 00000 = -34.5 dB -* -* IXJCTL_SC_RXG sets the Receive gain -* IXJCTL_SC_TXG sets the Transmit gain -* -******************************************************************************/ -#define IXJCTL_SC_RXG _IOW ('q', 0xEA, int) -#define IXJCTL_SC_TXG _IOW ('q', 0xEB, int) - -/****************************************************************************** -* -* The intercom IOCTL's short the output from one card to the input of the -* other and vice versa (actually done in the DSP read function). It is only -* necessary to execute the IOCTL on one card, but it is necessary to have -* both devices open to be able to detect hook switch changes. The record -* codec and rate of each card must match the playback codec and rate of -* the other card for this to work properly. -* -******************************************************************************/ - -#define IXJCTL_INTERCOM_START _IOW ('q', 0xFD, int) -#define IXJCTL_INTERCOM_STOP _IOW ('q', 0xFE, int) - -/****************************************************************************** - * - * new structure for accessing raw filter information - * - ******************************************************************************/ - -typedef struct { - unsigned int filter; - char enable; - unsigned int coeff[19]; -} IXJ_FILTER_RAW; - -#endif diff --git a/include/uapi/linux/telephony.h b/include/uapi/linux/telephony.h deleted file mode 100644 index d2c9f7105f4b..000000000000 --- a/include/uapi/linux/telephony.h +++ /dev/null @@ -1,263 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ -/****************************************************************************** - * - * telephony.h - * - * Basic Linux Telephony Interface - * - * (c) Copyright 1999-2001 Quicknet Technologies, 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. - * - * Authors: Ed Okerson, <eokerson@quicknet.net> - * Greg Herlein, <gherlein@quicknet.net> - * - * Contributors: Alan Cox, <alan@lxorguk.ukuu.org.uk> - * David W. Erhart, <derhart@quicknet.net> - * - * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT - * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET - * TECHNOLOGIES, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION - * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - *****************************************************************************/ - -#ifndef TELEPHONY_H -#define TELEPHONY_H - -#define TELEPHONY_VERSION 3013 - -#define PHONE_VENDOR_IXJ 1 -#define PHONE_VENDOR_QUICKNET PHONE_VENDOR_IXJ -#define PHONE_VENDOR_VOICETRONIX 2 -#define PHONE_VENDOR_ACULAB 3 -#define PHONE_VENDOR_DIGI 4 -#define PHONE_VENDOR_FRANKLIN 5 - -/****************************************************************************** - * Vendor Summary Information Area - * - * Quicknet Technologies, Inc. - makes low density analog telephony cards - * with audio compression, POTS and PSTN interfaces (www.quicknet.net) - * - * (other vendors following this API shuld add a short description of - * the telephony products they support under Linux) - * - *****************************************************************************/ -#define QTI_PHONEJACK 100 -#define QTI_LINEJACK 300 -#define QTI_PHONEJACK_LITE 400 -#define QTI_PHONEJACK_PCI 500 -#define QTI_PHONECARD 600 - -/****************************************************************************** -* -* The capabilities ioctls can inform you of the capabilities of each phone -* device installed in your system. The PHONECTL_CAPABILITIES ioctl -* returns an integer value indicating the number of capabilities the -* device has. The PHONECTL_CAPABILITIES_LIST will fill an array of -* capability structs with all of its capabilities. The -* PHONECTL_CAPABILITIES_CHECK takes a single capability struct and returns -* a TRUE if the device has that capability, otherwise it returns false. -* -******************************************************************************/ -typedef enum { - vendor = 0, - device, - port, - codec, - dsp -} phone_cap; - -struct phone_capability { - char desc[80]; - phone_cap captype; - int cap; - int handle; -}; - -typedef enum { - pots = 0, - pstn, - handset, - speaker -} phone_ports; - -#define PHONE_CAPABILITIES _IO ('q', 0x80) -#define PHONE_CAPABILITIES_LIST _IOR ('q', 0x81, struct phone_capability *) -#define PHONE_CAPABILITIES_CHECK _IOW ('q', 0x82, struct phone_capability *) - -typedef struct { - char month[3]; - char day[3]; - char hour[3]; - char min[3]; - int numlen; - char number[11]; - int namelen; - char name[80]; -} PHONE_CID; - -#define PHONE_RING _IO ('q', 0x83) -#define PHONE_HOOKSTATE _IO ('q', 0x84) -#define PHONE_MAXRINGS _IOW ('q', 0x85, char) -#define PHONE_RING_CADENCE _IOW ('q', 0x86, short) -#define OLD_PHONE_RING_START _IO ('q', 0x87) -#define PHONE_RING_START _IOW ('q', 0x87, PHONE_CID *) -#define PHONE_RING_STOP _IO ('q', 0x88) - -#define USA_RING_CADENCE 0xC0C0 - -#define PHONE_REC_CODEC _IOW ('q', 0x89, int) -#define PHONE_REC_START _IO ('q', 0x8A) -#define PHONE_REC_STOP _IO ('q', 0x8B) -#define PHONE_REC_DEPTH _IOW ('q', 0x8C, int) -#define PHONE_FRAME _IOW ('q', 0x8D, int) -#define PHONE_REC_VOLUME _IOW ('q', 0x8E, int) -#define PHONE_REC_VOLUME_LINEAR _IOW ('q', 0xDB, int) -#define PHONE_REC_LEVEL _IO ('q', 0x8F) - -#define PHONE_PLAY_CODEC _IOW ('q', 0x90, int) -#define PHONE_PLAY_START _IO ('q', 0x91) -#define PHONE_PLAY_STOP _IO ('q', 0x92) -#define PHONE_PLAY_DEPTH _IOW ('q', 0x93, int) -#define PHONE_PLAY_VOLUME _IOW ('q', 0x94, int) -#define PHONE_PLAY_VOLUME_LINEAR _IOW ('q', 0xDC, int) -#define PHONE_PLAY_LEVEL _IO ('q', 0x95) -#define PHONE_DTMF_READY _IOR ('q', 0x96, int) -#define PHONE_GET_DTMF _IOR ('q', 0x97, int) -#define PHONE_GET_DTMF_ASCII _IOR ('q', 0x98, int) -#define PHONE_DTMF_OOB _IOW ('q', 0x99, int) -#define PHONE_EXCEPTION _IOR ('q', 0x9A, int) -#define PHONE_PLAY_TONE _IOW ('q', 0x9B, char) -#define PHONE_SET_TONE_ON_TIME _IOW ('q', 0x9C, int) -#define PHONE_SET_TONE_OFF_TIME _IOW ('q', 0x9D, int) -#define PHONE_GET_TONE_ON_TIME _IO ('q', 0x9E) -#define PHONE_GET_TONE_OFF_TIME _IO ('q', 0x9F) -#define PHONE_GET_TONE_STATE _IO ('q', 0xA0) -#define PHONE_BUSY _IO ('q', 0xA1) -#define PHONE_RINGBACK _IO ('q', 0xA2) -#define PHONE_DIALTONE _IO ('q', 0xA3) -#define PHONE_CPT_STOP _IO ('q', 0xA4) - -#define PHONE_PSTN_SET_STATE _IOW ('q', 0xA4, int) -#define PHONE_PSTN_GET_STATE _IO ('q', 0xA5) - -#define PSTN_ON_HOOK 0 -#define PSTN_RINGING 1 -#define PSTN_OFF_HOOK 2 -#define PSTN_PULSE_DIAL 3 - -/****************************************************************************** -* -* The wink duration is tunable with this ioctl. The default wink duration -* is 320ms. You do not need to use this ioctl if you do not require a -* different wink duration. -* -******************************************************************************/ -#define PHONE_WINK_DURATION _IOW ('q', 0xA6, int) -#define PHONE_WINK _IOW ('q', 0xAA, int) - -/****************************************************************************** -* -* Codec Definitions -* -******************************************************************************/ -typedef enum { - G723_63 = 1, - G723_53 = 2, - TS85 = 3, - TS48 = 4, - TS41 = 5, - G728 = 6, - G729 = 7, - ULAW = 8, - ALAW = 9, - LINEAR16 = 10, - LINEAR8 = 11, - WSS = 12, - G729B = 13 -} phone_codec; - -struct phone_codec_data -{ - phone_codec type; - unsigned short buf_min, buf_opt, buf_max; -}; - -#define PHONE_QUERY_CODEC _IOWR ('q', 0xA7, struct phone_codec_data *) -#define PHONE_PSTN_LINETEST _IO ('q', 0xA8) - -/****************************************************************************** -* -* This controls the VAD/CNG functionality of G.723.1. The driver will -* always pass full size frames, any unused bytes will be padded with zeros, -* and frames passed to the driver should also be padded with zeros. The -* frame type is encoded in the least significant two bits of the first -* WORD of the frame as follows: -* -* bits 1-0 Frame Type Data Rate Significant Words -* 00 0 G.723.1 6.3 12 -* 01 1 G.723.1 5.3 10 -* 10 2 VAD/CNG 2 -* 11 3 Repeat last CNG 2 bits -* -******************************************************************************/ -#define PHONE_VAD _IOW ('q', 0xA9, int) - - -/****************************************************************************** -* -* The exception structure allows us to multiplex multiple events onto the -* select() exception set. If any of these flags are set select() will -* return with a positive indication on the exception set. The dtmf_ready -* bit indicates if there is data waiting in the DTMF buffer. The -* hookstate bit is set if there is a change in hookstate status, it does not -* indicate the current state of the hookswitch. The pstn_ring bit -* indicates that the DAA on a LineJACK card has detected ring voltage on -* the PSTN port. The caller_id bit indicates that caller_id data has been -* received and is available. The pstn_wink bit indicates that the DAA on -* the LineJACK has received a wink from the telco switch. The f0, f1, f2 -* and f3 bits indicate that the filter has been triggered by detecting the -* frequency programmed into that filter. -* -* The remaining bits should be set to zero. They will become defined over time -* for other interface cards and their needs. -* -******************************************************************************/ -struct phone_except -{ - unsigned int dtmf_ready:1; - unsigned int hookstate:1; - unsigned int pstn_ring:1; - unsigned int caller_id:1; - unsigned int pstn_wink:1; - unsigned int f0:1; - unsigned int f1:1; - unsigned int f2:1; - unsigned int f3:1; - unsigned int flash:1; - unsigned int fc0:1; - unsigned int fc1:1; - unsigned int fc2:1; - unsigned int fc3:1; - unsigned int reserved:18; -}; - -union telephony_exception { - struct phone_except bits; - unsigned int bytes; -}; - - -#endif /* TELEPHONY_H */ - diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c index e2d329099bf7..14436f4ca6bd 100644 --- a/lib/int_sqrt.c +++ b/lib/int_sqrt.c @@ -38,3 +38,33 @@ unsigned long int_sqrt(unsigned long x) return y; } EXPORT_SYMBOL(int_sqrt); + +#if BITS_PER_LONG < 64 +/** + * int_sqrt64 - strongly typed int_sqrt function when minimum 64 bit input + * is expected. + * @x: 64bit integer of which to calculate the sqrt + */ +u32 int_sqrt64(u64 x) +{ + u64 b, m, y = 0; + + if (x <= ULONG_MAX) + return int_sqrt((unsigned long) x); + + m = 1ULL << (fls64(x) & ~1ULL); + while (m != 0) { + b = y + m; + y >>= 1; + + if (x >= b) { + x -= b; + y += m; + } + m >>= 2; + } + + return y; +} +EXPORT_SYMBOL(int_sqrt64); +#endif |